Version: SMASH-2.0
stringprocess.cc
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (c) 2017-
4  * SMASH Team
5  *
6  * GNU General Public License (GPLv3 or later)
7  *
8  */
9 
10 #include <array>
11 
12 #include "smash/angles.h"
13 #include "smash/kinematics.h"
14 #include "smash/pow.h"
15 #include "smash/random.h"
16 #include "smash/stringprocess.h"
17 
18 namespace smash {
19 static constexpr int LOutput = LogArea::Output::id;
20 
22  double string_tension, double time_formation, double gluon_beta,
23  double gluon_pmin, double quark_alpha, double quark_beta,
24  double strange_supp, double diquark_supp, double sigma_perp,
25  double stringz_a_leading, double stringz_b_leading, double stringz_a,
26  double stringz_b, double string_sigma_T, double factor_t_form,
27  bool mass_dependent_formation_times, double prob_proton_to_d_uu,
28  bool separate_fragment_baryon, double popcorn_rate)
29  : pmin_gluon_lightcone_(gluon_pmin),
30  pow_fgluon_beta_(gluon_beta),
31  pow_fquark_alpha_(quark_alpha),
32  pow_fquark_beta_(quark_beta),
33  sigma_qperp_(sigma_perp),
34  stringz_a_leading_(stringz_a_leading),
35  stringz_b_leading_(stringz_b_leading),
36  stringz_a_produce_(stringz_a),
37  stringz_b_produce_(stringz_b),
38  strange_supp_(strange_supp),
39  diquark_supp_(diquark_supp),
40  popcorn_rate_(popcorn_rate),
41  string_sigma_T_(string_sigma_T),
42  kappa_tension_string_(string_tension),
43  additional_xsec_supp_(0.7),
44  time_formation_const_(time_formation),
45  soft_t_form_(factor_t_form),
46  time_collision_(0.),
47  mass_dependent_formation_times_(mass_dependent_formation_times),
48  prob_proton_to_d_uu_(prob_proton_to_d_uu),
49  separate_fragment_baryon_(separate_fragment_baryon) {
50  // setup and initialize pythia for fragmentation
51  pythia_hadron_ = make_unique<Pythia8::Pythia>(PYTHIA_XML_DIR, false);
52  /* turn off all parton-level processes to implement only hadronization */
53  pythia_hadron_->readString("ProcessLevel:all = off");
54  common_setup_pythia(pythia_hadron_.get(), strange_supp, diquark_supp,
55  popcorn_rate, stringz_a, stringz_b, string_sigma_T);
56 
57  /* initialize PYTHIA */
58  pythia_hadron_->init();
59 
60  /*
61  * The const_cast<type>() function is used to obtain the reference of the
62  * PrivateInfo object in the pythia_hadron_.
63  * This cast is needed since Pythia 8.302 which included a major architecture
64  * change. The Info object of a Pythia object is now private, only a const
65  * reference can be obtained.
66  * In order to reference the PrivateInfo object during initialization, we
67  * cast the const reference to obtain the stored address.
68  */
69  pythia_sigmatot_.initInfoPtr(
70  const_cast<Pythia8::Info &>(pythia_hadron_->info));
71  pythia_sigmatot_.init();
72 
73  pythia_stringflav_.initInfoPtr(
74  const_cast<Pythia8::Info &>(pythia_hadron_->info));
75  pythia_stringflav_.init();
76 
77  event_intermediate_.init("intermediate partons",
78  &pythia_hadron_->particleData);
79 
80  for (int imu = 0; imu < 3; imu++) {
81  evecBasisAB_[imu] = ThreeVector(0., 0., 0.);
82  }
83 
84  final_state_.clear();
85 }
86 
87 void StringProcess::common_setup_pythia(Pythia8::Pythia *pythia_in,
88  double strange_supp,
89  double diquark_supp,
90  double popcorn_rate, double stringz_a,
91  double stringz_b,
92  double string_sigma_T) {
93  // choose parametrization for mass-dependent width
94  pythia_in->readString("ParticleData:modeBreitWigner = 4");
95  /* choose minimum transverse momentum scale
96  * involved in partonic interactions */
97  pythia_in->readString("MultipartonInteractions:pTmin = 1.5");
98  pythia_in->readString("MultipartonInteractions:nSample = 10000");
99  // transverse momentum spread in string fragmentation
100  pythia_in->readString("StringPT:sigma = " + std::to_string(string_sigma_T));
101  // diquark suppression factor in string fragmentation
102  pythia_in->readString("StringFlav:probQQtoQ = " +
103  std::to_string(diquark_supp));
104  // strangeness suppression factor in string fragmentation
105  pythia_in->readString("StringFlav:probStoUD = " +
106  std::to_string(strange_supp));
107  pythia_in->readString("StringFlav:popcornRate = " +
108  std::to_string(popcorn_rate));
109  // parameters for the fragmentation function
110  pythia_in->readString("StringZ:aLund = " + std::to_string(stringz_a));
111  pythia_in->readString("StringZ:bLund = " + std::to_string(stringz_b));
112 
113  // manually set the parton distribution function
114  pythia_in->readString("PDF:pSet = 13");
115  pythia_in->readString("PDF:pSetB = 13");
116  pythia_in->readString("PDF:piSet = 1");
117  pythia_in->readString("PDF:piSetB = 1");
118  pythia_in->readString("Beams:idA = 2212");
119  pythia_in->readString("Beams:idB = 2212");
120  pythia_in->readString("Beams:eCM = 10.");
121 
122  // set PYTHIA random seed from outside
123  pythia_in->readString("Random:setSeed = on");
124  // suppress unnecessary output
125  pythia_in->readString("Print:quiet = on");
126  // No resonance decays, since the resonances will be handled by SMASH
127  pythia_in->readString("HadronLevel:Decay = off");
128  // set particle masses and widths in PYTHIA to be same with those in SMASH
129  for (auto &ptype : ParticleType::list_all()) {
130  int pdgid = ptype.pdgcode().get_decimal();
131  double mass_pole = ptype.mass();
132  double width_pole = ptype.width_at_pole();
133  // check if the particle species is in PYTHIA
134  if (pythia_in->particleData.isParticle(pdgid)) {
135  // set mass and width in PYTHIA
136  pythia_in->particleData.m0(pdgid, mass_pole);
137  pythia_in->particleData.mWidth(pdgid, width_pole);
138  } else if (pdgid == 310 || pdgid == 130) {
139  // set mass and width of Kaon-L and Kaon-S
140  pythia_in->particleData.m0(pdgid, kaon_mass);
141  pythia_in->particleData.mWidth(pdgid, 0.);
142  }
143  }
144 
145  // make energy-momentum conservation in PYTHIA more precise
146  pythia_in->readString("Check:epTolErr = 1e-6");
147  pythia_in->readString("Check:epTolWarn = 1e-8");
148 }
149 
150 // compute the formation time and fill the arrays with final-state particles
151 int StringProcess::append_final_state(ParticleList &intermediate_particles,
152  const FourVector &uString,
153  const ThreeVector &evecLong) {
154  int nfrag = 0;
155  int bstring = 0;
156 
157  for (ParticleData &data : intermediate_particles) {
158  nfrag += 1;
159  bstring += data.pdgcode().baryon_number();
160  }
161  assert(nfrag > 0);
162 
163  /* compute the cross section scaling factor for leading hadrons
164  * based on the number of valence quarks. */
165  assign_all_scaling_factors(bstring, intermediate_particles, evecLong,
167 
168  // Velocity three-vector to perform Lorentz boost.
169  const ThreeVector vstring = uString.velocity();
170 
171  // compute the formation times of hadrons
172  for (int i = 0; i < nfrag; i++) {
173  ThreeVector velocity = intermediate_particles[i].momentum().velocity();
174  double gamma = 1. / intermediate_particles[i].inverse_gamma();
175  // boost 4-momentum into the center of mass frame
176  FourVector momentum =
177  intermediate_particles[i].momentum().lorentz_boost(-vstring);
178  intermediate_particles[i].set_4momentum(momentum);
179 
181  // set the formation time and position in the rest frame of string
182  double tau_prod = M_SQRT2 * intermediate_particles[i].effective_mass() /
184  double t_prod = tau_prod * gamma;
185  FourVector fragment_position = FourVector(t_prod, t_prod * velocity);
186  /* boost formation position into the center of mass frame
187  * and then into the lab frame */
188  fragment_position = fragment_position.lorentz_boost(-vstring);
189  fragment_position = fragment_position.lorentz_boost(-vcomAB_);
190  intermediate_particles[i].set_slow_formation_times(
192  soft_t_form_ * fragment_position.x0() + time_collision_);
193  } else {
194  ThreeVector v_calc = momentum.lorentz_boost(-vcomAB_).velocity();
195  double gamma_factor = 1.0 / std::sqrt(1 - (v_calc).sqr());
196  intermediate_particles[i].set_slow_formation_times(
198  time_formation_const_ * gamma_factor + time_collision_);
199  }
200 
201  final_state_.push_back(intermediate_particles[i]);
202  }
203 
204  return nfrag;
205 }
206 
207 void StringProcess::init(const ParticleList &incoming, double tcoll) {
208  PDGcodes_[0] = incoming[0].pdgcode();
209  PDGcodes_[1] = incoming[1].pdgcode();
210  massA_ = incoming[0].effective_mass();
211  massB_ = incoming[1].effective_mass();
212 
213  plab_[0] = incoming[0].momentum();
214  plab_[1] = incoming[1].momentum();
215 
216  // compute sqrts and velocity of the center of mass.
217  sqrtsAB_ = (plab_[0] + plab_[1]).abs();
218  ucomAB_ = (plab_[0] + plab_[1]) / sqrtsAB_;
220 
221  pcom_[0] = plab_[0].lorentz_boost(vcomAB_);
222  pcom_[1] = plab_[1].lorentz_boost(vcomAB_);
223 
224  const double pabscomAB = pCM(sqrtsAB_, massA_, massB_);
225  ThreeVector evec_coll = pcom_[0].threevec() / pabscomAB;
227 
229 
230  time_collision_ = tcoll;
231 }
232 
233 /* single diffractive
234  * is_AB_to_AX = true : A + B -> A + X
235  * is_AB_to_AX = false : A + B -> X + B */
236 bool StringProcess::next_SDiff(bool is_AB_to_AX) {
237  NpartFinal_ = 0;
238  NpartString_[0] = 0;
239  NpartString_[1] = 0;
240  final_state_.clear();
241 
242  double massH = is_AB_to_AX ? massA_ : massB_;
243  double mstrMin = is_AB_to_AX ? massB_ : massA_;
244  double mstrMax = sqrtsAB_ - massH;
245 
246  int idqX1, idqX2;
247  double QTrn, QTrx, QTry;
248  double pabscomHX_sqr, massX;
249 
250  // decompose hadron into quarks
251  make_string_ends(is_AB_to_AX ? PDGcodes_[1] : PDGcodes_[0], idqX1, idqX2,
253  // string mass must be larger than threshold set by PYTHIA.
254  mstrMin = pythia_hadron_->particleData.m0(idqX1) +
255  pythia_hadron_->particleData.m0(idqX2);
256  // this threshold cannot be larger than maximum of allowed string mass.
257  if (mstrMin > mstrMax) {
258  return false;
259  }
260  // sample the transverse momentum transfer
261  QTrx = random::normal(0., sigma_qperp_ * M_SQRT1_2);
262  QTry = random::normal(0., sigma_qperp_ * M_SQRT1_2);
263  QTrn = std::sqrt(QTrx * QTrx + QTry * QTry);
264  /* sample the string mass and
265  * evaluate the three-momenta of hadron and string. */
266  massX = random::power(-1.0, mstrMin, mstrMax);
267  pabscomHX_sqr = pCM_sqr(sqrtsAB_, massH, massX);
268  /* magnitude of the three momentum must be larger
269  * than the transverse momentum. */
270  const bool foundPabsX = pabscomHX_sqr > QTrn * QTrn;
271 
272  if (!foundPabsX) {
273  return false;
274  }
275  double sign_direction = is_AB_to_AX ? 1. : -1.;
276  // determine three momentum of the final state hadron
277  const ThreeVector cm_momentum =
278  sign_direction *
279  (evecBasisAB_[0] * std::sqrt(pabscomHX_sqr - QTrn * QTrn) +
280  evecBasisAB_[1] * QTrx + evecBasisAB_[2] * QTry);
281  const FourVector pstrHcom(std::sqrt(pabscomHX_sqr + massH * massH),
282  cm_momentum);
283  const FourVector pstrXcom(std::sqrt(pabscomHX_sqr + massX * massX),
284  -cm_momentum);
285 
286  const FourVector ustrXcom = pstrXcom / massX;
287  /* determine direction in which the string is stretched.
288  * this is set to be same with the the collision axis
289  * in the center of mass frame. */
290  const ThreeVector threeMomentum =
291  is_AB_to_AX ? pcom_[1].threevec() : pcom_[0].threevec();
292  const FourVector pnull = FourVector(threeMomentum.abs(), threeMomentum);
293  const FourVector prs = pnull.lorentz_boost(ustrXcom.velocity());
294  ThreeVector evec = prs.threevec() / prs.threevec().abs();
295  // perform fragmentation and add particles to final_state.
296  ParticleList new_intermediate_particles;
297  int nfrag = fragment_string(idqX1, idqX2, massX, evec, true, false,
298  new_intermediate_particles);
299  if (nfrag < 1) {
300  NpartString_[0] = 0;
301  return false;
302  }
303  NpartString_[0] =
304  append_final_state(new_intermediate_particles, ustrXcom, evec);
305 
306  NpartString_[1] = 1;
307  PdgCode hadron_code = is_AB_to_AX ? PDGcodes_[0] : PDGcodes_[1];
308  ParticleData new_particle(ParticleType::find(hadron_code));
309  new_particle.set_4momentum(pstrHcom);
310  new_particle.set_cross_section_scaling_factor(1.);
311  new_particle.set_formation_time(time_collision_);
312  final_state_.push_back(new_particle);
313 
315  return true;
316 }
317 
319  const std::array<std::array<int, 2>, 2> &quarks,
320  const std::array<FourVector, 2> &pstr_com, std::array<double, 2> &m_str,
321  std::array<ThreeVector, 2> &evec_str) {
322  std::array<bool, 2> found_mass;
323  for (int i = 0; i < 2; i++) {
324  found_mass[i] = false;
325 
326  m_str[i] = pstr_com[i].sqr();
327  m_str[i] = (m_str[i] > 0.) ? std::sqrt(m_str[i]) : 0.;
328  const double threshold = pythia_hadron_->particleData.m0(quarks[i][0]) +
329  pythia_hadron_->particleData.m0(quarks[i][1]);
330  // string mass must be larger than threshold set by PYTHIA.
331  if (m_str[i] > threshold) {
332  found_mass[i] = true;
333  /* Determine direction in which string i is stretched.
334  * This is set to be same with the collision axis
335  * in the center of mass frame.
336  * Initial state partons inside incoming hadrons are
337  * moving along the collision axis,
338  * which is parallel to three momenta of incoming hadrons
339  * in the center of mass frame.
340  * Given that partons are assumed to be massless,
341  * their four momenta are null vectors and parallel to pnull.
342  * If we take unit three-vector of prs,
343  * which is pnull in the rest frame of string,
344  * it would be the direction in which string ends are moving. */
345  const ThreeVector mom = pcom_[i].threevec();
346  const FourVector pnull(mom.abs(), mom);
347  const FourVector prs = pnull.lorentz_boost(pstr_com[i].velocity());
348  evec_str[i] = prs.threevec() / prs.threevec().abs();
349  }
350  }
351 
352  return found_mass[0] && found_mass[1];
353 }
354 
356  const std::array<std::array<int, 2>, 2> &quarks,
357  const std::array<FourVector, 2> &pstr_com,
358  const std::array<double, 2> &m_str,
359  const std::array<ThreeVector, 2> &evec_str, bool flip_string_ends,
360  bool separate_fragment_baryon) {
361  const std::array<FourVector, 2> ustr_com = {pstr_com[0] / m_str[0],
362  pstr_com[1] / m_str[1]};
363  for (int i = 0; i < 2; i++) {
364  ParticleList new_intermediate_particles;
365 
366  // determine direction in which string i is stretched.
367  ThreeVector evec = evec_str[i];
368  // perform fragmentation and add particles to final_state.
369  int nfrag = fragment_string(quarks[i][0], quarks[i][1], m_str[i], evec,
370  flip_string_ends, separate_fragment_baryon,
371  new_intermediate_particles);
372  if (nfrag <= 0) {
373  NpartString_[i] = 0;
374  return false;
375  }
376  NpartString_[i] =
377  append_final_state(new_intermediate_particles, ustr_com[i], evec);
378  assert(nfrag == NpartString_[i]);
379  }
380  if ((NpartString_[0] > 0) && (NpartString_[1] > 0)) {
382  return true;
383  }
384  return false;
385 }
386 
387 // double-diffractive : A + B -> X + X
389  NpartFinal_ = 0;
390  NpartString_[0] = 0;
391  NpartString_[1] = 0;
392  final_state_.clear();
393 
394  std::array<std::array<int, 2>, 2> quarks;
395  std::array<FourVector, 2> pstr_com;
396  std::array<double, 2> m_str;
397  std::array<ThreeVector, 2> evec_str;
398  ThreeVector threeMomentum;
399 
400  // decompose hadron into quark (and diquark) contents
401  make_string_ends(PDGcodes_[0], quarks[0][0], quarks[0][1],
403  make_string_ends(PDGcodes_[1], quarks[1][0], quarks[1][1],
405  // sample the lightcone momentum fraction carried by gluons
406  const double xmin_gluon_fraction = pmin_gluon_lightcone_ / sqrtsAB_;
407  const double xfracA =
408  random::beta_a0(xmin_gluon_fraction, pow_fgluon_beta_ + 1.);
409  const double xfracB =
410  random::beta_a0(xmin_gluon_fraction, pow_fgluon_beta_ + 1.);
411  // sample the transverse momentum transfer
412  const double QTrx = random::normal(0., sigma_qperp_ * M_SQRT1_2);
413  const double QTry = random::normal(0., sigma_qperp_ * M_SQRT1_2);
414  const double QTrn = std::sqrt(QTrx * QTrx + QTry * QTry);
415  // evaluate the lightcone momentum transfer
416  const double QPos = -QTrn * QTrn / (2. * xfracB * PNegB_);
417  const double QNeg = QTrn * QTrn / (2. * xfracA * PPosA_);
418  // compute four-momentum of string 1
419  threeMomentum =
420  evecBasisAB_[0] * (PPosA_ + QPos - PNegA_ - QNeg) * M_SQRT1_2 +
421  evecBasisAB_[1] * QTrx + evecBasisAB_[2] * QTry;
422  pstr_com[0] =
423  FourVector((PPosA_ + QPos + PNegA_ + QNeg) * M_SQRT1_2, threeMomentum);
424  // compute four-momentum of string 2
425  threeMomentum =
426  evecBasisAB_[0] * (PPosB_ - QPos - PNegB_ + QNeg) * M_SQRT1_2 -
427  evecBasisAB_[1] * QTrx - evecBasisAB_[2] * QTry;
428  pstr_com[1] =
429  FourVector((PPosB_ - QPos + PNegB_ - QNeg) * M_SQRT1_2, threeMomentum);
430 
431  const bool found_masses =
432  set_mass_and_direction_2strings(quarks, pstr_com, m_str, evec_str);
433  if (!found_masses) {
434  return false;
435  }
436  const bool flip_string_ends = true;
437  const bool success = make_final_state_2strings(
438  quarks, pstr_com, m_str, evec_str, flip_string_ends, false);
439  return success;
440 }
441 
442 // soft non-diffractive
444  NpartFinal_ = 0;
445  NpartString_[0] = 0;
446  NpartString_[1] = 0;
447  final_state_.clear();
448 
449  std::array<std::array<int, 2>, 2> quarks;
450  std::array<FourVector, 2> pstr_com;
451  std::array<double, 2> m_str;
452  std::array<ThreeVector, 2> evec_str;
453 
454  // decompose hadron into quark (and diquark) contents
455  int idqA1, idqA2, idqB1, idqB2;
458 
459  const int bar_a = PDGcodes_[0].baryon_number(),
460  bar_b = PDGcodes_[1].baryon_number();
461  if (bar_a == 1 || // baryon-baryon, baryon-meson, baryon-antibaryon
462  (bar_a == 0 && bar_b == 1) || // meson-baryon
463  (bar_a == 0 && bar_b == 0)) { // meson-meson
464  quarks[0][0] = idqB1;
465  quarks[0][1] = idqA2;
466  quarks[1][0] = idqA1;
467  quarks[1][1] = idqB2;
468  } else if (((bar_a == 0) && (bar_b == -1)) || // meson-antibaryon
469  (bar_a == -1)) { // antibaryon-baryon, antibaryon-meson,
470  // antibaryon-antibaryon
471  quarks[0][0] = idqA1;
472  quarks[0][1] = idqB2;
473  quarks[1][0] = idqB1;
474  quarks[1][1] = idqA2;
475  } else {
476  std::stringstream ss;
477  ss << " StringProcess::next_NDiff : baryonA = " << bar_a
478  << ", baryonB = " << bar_b;
479  throw std::runtime_error(ss.str());
480  }
481  // sample the lightcone momentum fraction carried by quarks
482  const double xfracA = random::beta(pow_fquark_alpha_, pow_fquark_beta_);
483  const double xfracB = random::beta(pow_fquark_alpha_, pow_fquark_beta_);
484  // sample the transverse momentum transfer
485  const double QTrx = random::normal(0., sigma_qperp_ * M_SQRT1_2);
486  const double QTry = random::normal(0., sigma_qperp_ * M_SQRT1_2);
487  const double QTrn = std::sqrt(QTrx * QTrx + QTry * QTry);
488  // evaluate the lightcone momentum transfer
489  const double QPos = -QTrn * QTrn / (2. * xfracB * PNegB_);
490  const double QNeg = QTrn * QTrn / (2. * xfracA * PPosA_);
491  const double dPPos = -xfracA * PPosA_ - QPos;
492  const double dPNeg = xfracB * PNegB_ - QNeg;
493  // compute four-momentum of string 1
494  ThreeVector threeMomentum =
495  evecBasisAB_[0] * (PPosA_ + dPPos - PNegA_ - dPNeg) * M_SQRT1_2 +
496  evecBasisAB_[1] * QTrx + evecBasisAB_[2] * QTry;
497  pstr_com[0] =
498  FourVector((PPosA_ + dPPos + PNegA_ + dPNeg) * M_SQRT1_2, threeMomentum);
499  m_str[0] = pstr_com[0].sqr();
500  // compute four-momentum of string 2
501  threeMomentum =
502  evecBasisAB_[0] * (PPosB_ - dPPos - PNegB_ + dPNeg) * M_SQRT1_2 -
503  evecBasisAB_[1] * QTrx - evecBasisAB_[2] * QTry;
504  pstr_com[1] =
505  FourVector((PPosB_ - dPPos + PNegB_ - dPNeg) * M_SQRT1_2, threeMomentum);
506 
507  const bool found_masses =
508  set_mass_and_direction_2strings(quarks, pstr_com, m_str, evec_str);
509  if (!found_masses) {
510  return false;
511  }
512  const bool flip_string_ends = false;
513  const bool success =
514  make_final_state_2strings(quarks, pstr_com, m_str, evec_str,
515  flip_string_ends, separate_fragment_baryon_);
516  return success;
517 }
518 
519 // hard non-diffractive
521  NpartFinal_ = 0;
522  final_state_.clear();
523 
524  logg[LPythia].debug("Hard non-diff. with ", PDGcodes_[0], " + ", PDGcodes_[1],
525  " at CM energy [GeV] ", sqrtsAB_);
526 
527  std::array<int, 2> pdg_for_pythia;
528  std::array<std::array<int, 5>, 2> excess_quark;
529  std::array<std::array<int, 5>, 2> excess_antiq;
530  for (int i = 0; i < 2; i++) {
531  for (int j = 0; j < 5; j++) {
532  excess_quark[i][j] = 0;
533  excess_antiq[i][j] = 0;
534  }
535 
536  // get PDG id used in PYTHIA event generation
537  pdg_for_pythia[i] = pdg_map_for_pythia(PDGcodes_[i]);
538  logg[LPythia].debug(" incoming particle ", i, " : ", PDGcodes_[i],
539  " is mapped onto ", pdg_for_pythia[i]);
540 
541  PdgCode pdgcode_for_pythia(std::to_string(pdg_for_pythia[i]));
542  /* evaluate how many more constituents incoming hadron has
543  * compared to the mapped one. */
544  find_excess_constituent(PDGcodes_[i], pdgcode_for_pythia, excess_quark[i],
545  excess_antiq[i]);
546  logg[LPythia].debug(" excess_quark[", i, "] = (", excess_quark[i][0],
547  ", ", excess_quark[i][1], ", ", excess_quark[i][2],
548  ", ", excess_quark[i][3], ", ", excess_quark[i][4],
549  ")");
550  logg[LPythia].debug(" excess_antiq[", i, "] = (", excess_antiq[i][0],
551  ", ", excess_antiq[i][1], ", ", excess_antiq[i][2],
552  ", ", excess_antiq[i][3], ", ", excess_antiq[i][4],
553  ")");
554  }
555 
556  std::pair<int, int> idAB{pdg_for_pythia[0], pdg_for_pythia[1]};
557 
558  // If an entry for the calculated particle IDs does not exist, create one and
559  // initialize it accordingly
560  if (hard_map_.count(idAB) == 0) {
561  hard_map_[idAB] = make_unique<Pythia8::Pythia>(PYTHIA_XML_DIR, false);
562  hard_map_[idAB]->readString("SoftQCD:nonDiffractive = on");
563  hard_map_[idAB]->readString("MultipartonInteractions:pTmin = 1.5");
564  hard_map_[idAB]->readString("HadronLevel:all = off");
565 
569 
570  hard_map_[idAB]->settings.flag("Beams:allowVariableEnergy", true);
571 
572  hard_map_[idAB]->settings.mode("Beams:idA", idAB.first);
573  hard_map_[idAB]->settings.mode("Beams:idB", idAB.second);
574  hard_map_[idAB]->settings.parm("Beams:eCM", sqrtsAB_);
575 
576  logg[LPythia].debug("Pythia object initialized with ", pdg_for_pythia[0],
577  " + ", pdg_for_pythia[1], " at CM energy [GeV] ",
578  sqrtsAB_);
579 
580  if (!hard_map_[idAB]->init()) {
581  throw std::runtime_error("Pythia failed to initialize.");
582  }
583  }
584 
585  // Else just pick the existing and initialized entry and go on
586  // Initialize Pythias random number generator using SMASHs seed
587  const int seed_new = random::uniform_int(1, maximum_rndm_seed_in_pythia);
588  hard_map_[idAB]->rndm.init(seed_new);
589  logg[LPythia].debug("hard_map_[", idAB.first, "][", idAB.second,
590  "] : rndm is initialized with seed ", seed_new);
591 
592  // Change the energy using the Pythia 8.302+ feature
593 
594  // Short notation for Pythia event
595  Pythia8::Event &event_hadron = pythia_hadron_->event;
596  logg[LPythia].debug("Pythia hard event created");
597  bool final_state_success = hard_map_[idAB]->next(sqrtsAB_);
598  logg[LPythia].debug("Pythia final state computed, success = ",
599  final_state_success);
600  if (!final_state_success) {
601  return false;
602  }
603 
604  ParticleList new_intermediate_particles;
605  ParticleList new_non_hadron_particles;
606 
607  Pythia8::Vec4 pSum = 0.;
608  event_intermediate_.reset();
609  /* Update the partonic intermediate state from PYTHIA output.
610  * Note that hadronization will be performed separately,
611  * after identification of strings and replacement of constituents. */
612  for (int i = 0; i < hard_map_[idAB]->event.size(); i++) {
613  if (hard_map_[idAB]->event[i].isFinal()) {
614  const int pdgid = hard_map_[idAB]->event[i].id();
615  Pythia8::Vec4 pquark = hard_map_[idAB]->event[i].p();
616  const double mass = hard_map_[idAB]->particleData.m0(pdgid);
617 
618  const int status = hard_map_[idAB]->event[i].status();
619  const int color = hard_map_[idAB]->event[i].col();
620  const int anticolor = hard_map_[idAB]->event[i].acol();
621 
622  pSum += pquark;
623  event_intermediate_.append(pdgid, status, color, anticolor, pquark, mass);
624  }
625  }
626  // add junctions to the intermediate state if there is any.
627  event_intermediate_.clearJunctions();
628  for (int i = 0; i < hard_map_[idAB]->event.sizeJunction(); i++) {
629  const int kind = hard_map_[idAB]->event.kindJunction(i);
630  std::array<int, 3> col;
631  for (int j = 0; j < 3; j++) {
632  col[j] = hard_map_[idAB]->event.colJunction(i, j);
633  }
634  event_intermediate_.appendJunction(kind, col[0], col[1], col[2]);
635  }
636  /* The zeroth entry of event record is supposed to have the information
637  * on the whole system. Specify the total momentum and invariant mass. */
638  event_intermediate_[0].p(pSum);
639  event_intermediate_[0].m(pSum.mCalc());
640 
641  /* Replace quark constituents according to the excess of valence quarks
642  * and then rescale momenta of partons by constant factor
643  * to fulfill the energy-momentum conservation. */
644  bool correct_constituents =
645  restore_constituent(event_intermediate_, excess_quark, excess_antiq);
646  if (!correct_constituents) {
647  logg[LPythia].debug("failed to find correct partonic constituents.");
648  return false;
649  }
650 
651  int npart = event_intermediate_.size();
652  int ipart = 0;
653  while (ipart < npart) {
654  const int pdgid = event_intermediate_[ipart].id();
655  if (event_intermediate_[ipart].isFinal() &&
656  !event_intermediate_[ipart].isParton() &&
657  !hard_map_[idAB]->particleData.isOctetHadron(pdgid)) {
658  logg[LPythia].debug("PDG ID from Pythia: ", pdgid);
660  logg[LPythia].debug("4-momentum from Pythia: ", momentum);
661  bool found_ptype =
662  append_intermediate_list(pdgid, momentum, new_non_hadron_particles);
663  if (!found_ptype) {
664  logg[LPythia].warn("PDG ID ", pdgid,
665  " does not exist in ParticleType - start over.");
666  final_state_success = false;
667  }
668  event_intermediate_.remove(ipart, ipart);
669  npart -= 1;
670  } else {
671  ipart += 1;
672  }
673  }
674 
675  bool hadronize_success = false;
676  bool find_forward_string = true;
677  logg[LPythia].debug("Hard non-diff: partonic process gives ",
678  event_intermediate_.size(), " partons.");
679  // identify and fragment strings until there is no parton left.
680  while (event_intermediate_.size() > 1) {
681  // dummy event to initialize the internal variables of PYTHIA.
682  pythia_hadron_->event.reset();
683  if (!pythia_hadron_->next()) {
684  logg[LPythia].debug(" Dummy event in hard string routine failed.");
685  hadronize_success = false;
686  break;
687  }
688 
689  if (event_intermediate_.sizeJunction() > 0) {
690  // identify string from a junction if there is any.
691  compose_string_junction(find_forward_string, event_intermediate_,
692  pythia_hadron_->event);
693  } else {
694  /* identify string from a most forward or backward parton.
695  * if there is no junction. */
696  compose_string_parton(find_forward_string, event_intermediate_,
697  pythia_hadron_->event);
698  }
699 
700  // fragment the (identified) string into hadrons.
701  hadronize_success = pythia_hadron_->forceHadronLevel(false);
702  logg[LPythia].debug("Pythia hadronized, success = ", hadronize_success);
703 
704  new_intermediate_particles.clear();
705  if (hadronize_success) {
706  for (int i = 0; i < event_hadron.size(); i++) {
707  if (event_hadron[i].isFinal()) {
708  int pythia_id = event_hadron[i].id();
709  logg[LPythia].debug("PDG ID from Pythia: ", pythia_id);
710  /* K_short and K_long need to be converted to K0
711  * since SMASH only knows K0 */
712  convert_KaonLS(pythia_id);
713 
714  /* evecBasisAB_[0] is a unit 3-vector in the collision axis,
715  * while evecBasisAB_[1] and evecBasisAB_[2] spans the transverse
716  * plane. Given that PYTHIA assumes z-direction to be the collision
717  * axis, pz from PYTHIA should be the momentum compoment in
718  * evecBasisAB_[0]. px and py are respectively the momentum components
719  * in two transverse directions evecBasisAB_[1] and evecBasisAB_[2].
720  */
721  FourVector momentum = reorient(event_hadron[i], evecBasisAB_);
722  logg[LPythia].debug("4-momentum from Pythia: ", momentum);
723  logg[LPythia].debug("appending the particle ", pythia_id,
724  " to the intermediate particle list.");
725  bool found_ptype = false;
726  if (event_hadron[i].isHadron()) {
727  found_ptype = append_intermediate_list(pythia_id, momentum,
728  new_intermediate_particles);
729  } else {
730  found_ptype = append_intermediate_list(pythia_id, momentum,
731  new_non_hadron_particles);
732  }
733  if (!found_ptype) {
734  logg[LPythia].warn("PDG ID ", pythia_id,
735  " does not exist in ParticleType - start over.");
736  hadronize_success = false;
737  }
738  }
739  }
740  }
741 
742  /* if hadronization is not successful,
743  * reset the event records, return false and then start over. */
744  if (!hadronize_success) {
745  break;
746  }
747 
748  FourVector uString = FourVector(1., 0., 0., 0.);
749  ThreeVector evec = find_forward_string ? evecBasisAB_[0] : -evecBasisAB_[0];
750  int nfrag = append_final_state(new_intermediate_particles, uString, evec);
751  NpartFinal_ += nfrag;
752 
753  find_forward_string = !find_forward_string;
754  }
755 
756  if (hadronize_success) {
757  // add the final state particles, which are not hadron.
758  for (ParticleData data : new_non_hadron_particles) {
759  data.set_cross_section_scaling_factor(1.);
760  data.set_formation_time(time_collision_);
761  final_state_.push_back(data);
762  }
763  } else {
764  final_state_.clear();
765  }
766 
767  return hadronize_success;
768 }
769 
771  PdgCode &pdg_mapped,
772  std::array<int, 5> &excess_quark,
773  std::array<int, 5> &excess_antiq) {
774  /* decompose PDG id of the actual hadron and mapped one
775  * to get the valence quark constituents */
776  std::array<int, 3> qcontent_actual = pdg_actual.quark_content();
777  std::array<int, 3> qcontent_mapped = pdg_mapped.quark_content();
778 
779  excess_quark = {0, 0, 0, 0, 0};
780  excess_antiq = {0, 0, 0, 0, 0};
781  for (int i = 0; i < 3; i++) {
782  if (qcontent_actual[i] > 0) { // quark content of the actual hadron
783  int j = qcontent_actual[i] - 1;
784  excess_quark[j] += 1;
785  }
786 
787  if (qcontent_mapped[i] > 0) { // quark content of the mapped hadron
788  int j = qcontent_mapped[i] - 1;
789  excess_quark[j] -= 1;
790  }
791 
792  if (qcontent_actual[i] < 0) { // antiquark content of the actual hadron
793  int j = std::abs(qcontent_actual[i]) - 1;
794  excess_antiq[j] += 1;
795  }
796 
797  if (qcontent_mapped[i] < 0) { // antiquark content of the mapped hadron
798  int j = std::abs(qcontent_mapped[i]) - 1;
799  excess_antiq[j] -= 1;
800  }
801  }
802 }
803 
805  Pythia8::Particle &particle, std::array<int, 5> &excess_constituent) {
806  // If the particle is neither quark nor diquark, nothing to do.
807  if (!particle.isQuark() && !particle.isDiquark()) {
808  return;
809  }
810 
811  // If there is no excess of constituents, nothing to do.
812  const std::array<int, 5> excess_null = {0, 0, 0, 0, 0};
813  if (excess_constituent == excess_null) {
814  return;
815  }
816 
817  int nq = 0;
818  std::array<int, 2> pdgid = {0, 0};
819  int spin_deg = 0;
820  int pdgid_new = 0;
821  if (particle.isQuark()) {
822  nq = 1;
823  pdgid[0] = particle.id();
824  } else if (particle.isDiquark()) {
825  nq = 2;
826  quarks_from_diquark(particle.id(), pdgid[0], pdgid[1], spin_deg);
827  }
828 
829  for (int iq = 0; iq < nq; iq++) {
830  int jq = std::abs(pdgid[iq]) - 1;
831  int k_select = 0;
832  std::vector<int> k_found;
833  k_found.clear();
834  // check if the constituent needs to be converted.
835  if (excess_constituent[jq] < 0) {
836  for (int k = 0; k < 5; k++) {
837  // check which specie it can be converted into.
838  if (k != jq && excess_constituent[k] > 0) {
839  k_found.push_back(k);
840  }
841  }
842  }
843 
844  // make a random selection of specie and update the excess of constituent.
845  if (k_found.size() > 0) {
846  const int l =
847  random::uniform_int(0, static_cast<int>(k_found.size()) - 1);
848  k_select = k_found[l];
849  /* flavor jq + 1 is converted into k_select + 1
850  * and excess_constituent is updated. */
851  pdgid[iq] = pdgid[iq] > 0 ? k_select + 1 : -(k_select + 1);
852  excess_constituent[jq] += 1;
853  excess_constituent[k_select] -= 1;
854  }
855  }
856 
857  // determine PDG id of the converted parton.
858  if (particle.isQuark()) {
859  pdgid_new = pdgid[0];
860  } else if (particle.isDiquark()) {
861  if (std::abs(pdgid[0]) < std::abs(pdgid[1])) {
862  std::swap(pdgid[0], pdgid[1]);
863  }
864 
865  pdgid_new = std::abs(pdgid[0]) * 1000 + std::abs(pdgid[1]) * 100;
866  if (std::abs(pdgid[0]) == std::abs(pdgid[1])) {
867  pdgid_new += 3;
868  } else {
869  pdgid_new += spin_deg;
870  }
871 
872  if (particle.id() < 0) {
873  pdgid_new *= -1;
874  }
875  }
876  logg[LPythia].debug(" parton id = ", particle.id(), " is converted to ",
877  pdgid_new);
878 
879  // update the constituent mass and energy.
880  Pythia8::Vec4 pquark = particle.p();
881  double mass_new = pythia_hadron_->particleData.m0(pdgid_new);
882  double e_new = std::sqrt(mass_new * mass_new + pquark.pAbs() * pquark.pAbs());
883  // update the particle object.
884  particle.id(pdgid_new);
885  particle.e(e_new);
886  particle.m(mass_new);
887 }
888 
890  Pythia8::Event &event_intermediate, std::array<int, 5> &nquark_total,
891  std::array<int, 5> &nantiq_total) {
892  for (int iflav = 0; iflav < 5; iflav++) {
893  nquark_total[iflav] = 0;
894  nantiq_total[iflav] = 0;
895  }
896 
897  for (int ip = 1; ip < event_intermediate.size(); ip++) {
898  if (!event_intermediate[ip].isFinal()) {
899  continue;
900  }
901  const int pdgid = event_intermediate[ip].id();
902  if (pdgid > 0) {
903  // quarks
904  for (int iflav = 0; iflav < 5; iflav++) {
905  nquark_total[iflav] +=
906  pythia_hadron_->particleData.nQuarksInCode(pdgid, iflav + 1);
907  }
908  } else {
909  // antiquarks
910  for (int iflav = 0; iflav < 5; iflav++) {
911  nantiq_total[iflav] += pythia_hadron_->particleData.nQuarksInCode(
912  std::abs(pdgid), iflav + 1);
913  }
914  }
915  }
916 }
917 
919  Pythia8::Event &event_intermediate, std::array<int, 5> &nquark_total,
920  std::array<int, 5> &nantiq_total, bool sign_constituent,
921  std::array<std::array<int, 5>, 2> &excess_constituent) {
922  Pythia8::Vec4 pSum = event_intermediate[0].p();
923 
924  /* compute total number of quark and antiquark constituents
925  * in the whole system. */
926  find_total_number_constituent(event_intermediate, nquark_total, nantiq_total);
927 
928  for (int iflav = 0; iflav < 5; iflav++) {
929  /* Find how many constituent will be in the system after
930  * changing the flavors.
931  * Note that nquark_total is number of constituent right after
932  * the pythia event (with mapped incoming hadrons), while the excess
933  * shows how many constituents we have more or less that nquark_total. */
934  int nquark_final =
935  excess_constituent[0][iflav] + excess_constituent[1][iflav];
936  if (sign_constituent) {
937  nquark_final += nquark_total[iflav];
938  } else {
939  nquark_final += nantiq_total[iflav];
940  }
941  /* Therefore, nquark_final should not be negative.
942  * negative nquark_final means that it will not be possible to
943  * find a constituent to change the flavor. */
944  bool enough_quark = nquark_final >= 0;
945  /* If that is the case, a gluon will be splitted into
946  * a quark-antiquark pair with the desired flavor. */
947  if (!enough_quark) {
948  logg[LPythia].debug(" not enough constituents with flavor ", iflav + 1,
949  " : try to split a gluon to qqbar.");
950  for (int ic = 0; ic < std::abs(nquark_final); ic++) {
951  /* Since each incoming hadron has its own count of the excess,
952  * it is necessary to find which one is problematic. */
953  int ih_mod = -1;
954  if (excess_constituent[0][iflav] < 0) {
955  ih_mod = 0;
956  } else {
957  ih_mod = 1;
958  }
959 
960  /* find the most forward or backward gluon
961  * depending on which incoming hadron is found to be an issue. */
962  int iforward = 1;
963  for (int ip = 2; ip < event_intermediate.size(); ip++) {
964  if (!event_intermediate[ip].isFinal() ||
965  !event_intermediate[ip].isGluon()) {
966  continue;
967  }
968 
969  const double y_gluon_current = event_intermediate[ip].y();
970  const double y_gluon_forward = event_intermediate[iforward].y();
971  if ((ih_mod == 0 && y_gluon_current > y_gluon_forward) ||
972  (ih_mod == 1 && y_gluon_current < y_gluon_forward)) {
973  iforward = ip;
974  }
975  }
976 
977  if (!event_intermediate[iforward].isGluon()) {
978  logg[LPythia].debug("There is no gluon to split into qqbar.");
979  return false;
980  }
981 
982  // four momentum of the original gluon
983  Pythia8::Vec4 pgluon = event_intermediate[iforward].p();
984 
985  const int pdgid = iflav + 1;
986  const double mass = pythia_hadron_->particleData.m0(pdgid);
987  const int status = event_intermediate[iforward].status();
988  /* color and anticolor indices.
989  * the color index of gluon goes to the quark, while
990  * the anticolor index goes to the antiquark */
991  const int col = event_intermediate[iforward].col();
992  const int acol = event_intermediate[iforward].acol();
993 
994  // three momenta of quark and antiquark
995  std::array<double, 2> px_quark;
996  std::array<double, 2> py_quark;
997  std::array<double, 2> pz_quark;
998  // energies of quark and antiquark
999  std::array<double, 2> e_quark;
1000  // four momenta of quark and antiquark
1001  std::array<Pythia8::Vec4, 2> pquark;
1002  // transverse momentum scale of string fragmentation
1003  const double sigma_qt_frag = pythia_hadron_->parm("StringPT:sigma");
1004  // sample relative transverse momentum between quark and antiquark
1005  const double qx = random::normal(0., sigma_qt_frag * M_SQRT1_2);
1006  const double qy = random::normal(0., sigma_qt_frag * M_SQRT1_2);
1007  // setup kinematics
1008  for (int isign = 0; isign < 2; isign++) {
1009  /* As the simplest assumption, the three momentum of gluon
1010  * is equally distributed to quark and antiquark.
1011  * Then, they have a relative transverse momentum. */
1012  px_quark[isign] = 0.5 * pgluon.px() + (isign == 0 ? 1. : -1.) * qx;
1013  py_quark[isign] = 0.5 * pgluon.py() + (isign == 0 ? 1. : -1.) * qy;
1014  pz_quark[isign] = 0.5 * pgluon.pz();
1015  e_quark[isign] =
1016  std::sqrt(mass * mass + px_quark[isign] * px_quark[isign] +
1017  py_quark[isign] * py_quark[isign] +
1018  pz_quark[isign] * pz_quark[isign]);
1019  pquark[isign] = Pythia8::Vec4(px_quark[isign], py_quark[isign],
1020  pz_quark[isign], e_quark[isign]);
1021  }
1022 
1023  /* Total energy is not conserved at this point,
1024  * but this will be cured later. */
1025  pSum += pquark[0] + pquark[1] - pgluon;
1026  // add quark and antiquark to the event record
1027  event_intermediate.append(pdgid, status, col, 0, pquark[0], mass);
1028  event_intermediate.append(-pdgid, status, 0, acol, pquark[1], mass);
1029  // then remove the gluon from the record
1030  event_intermediate.remove(iforward, iforward);
1031 
1032  logg[LPythia].debug(" gluon at iforward = ", iforward,
1033  " is splitted into ", pdgid, ",", -pdgid,
1034  " qqbar pair.");
1035  /* Increase the total number of quarks and antiquarks by 1,
1036  * as we have extra ones from a gluon. */
1037  nquark_total[iflav] += 1;
1038  nantiq_total[iflav] += 1;
1039  }
1040  }
1041  }
1042 
1043  /* The zeroth entry of event record is supposed to have the information
1044  * on the whole system. Specify the total momentum and invariant mass. */
1045  event_intermediate[0].p(pSum);
1046  event_intermediate[0].m(pSum.mCalc());
1047 
1048  return true;
1049 }
1050 
1052  std::array<int, 5> &nquark_total,
1053  std::array<std::array<int, 5>, 2> &excess_quark,
1054  std::array<std::array<int, 5>, 2> &excess_antiq) {
1055  for (int iflav = 0; iflav < 5; iflav++) {
1056  /* Find how many constituent will be in the system after
1057  * changing the flavors.
1058  * Note that nquark_total is number of constituent right after
1059  * the pythia event (with mapped incoming hadrons), while the excess
1060  * shows how many constituents we have more or less that nquark_total. */
1061  int nquark_final =
1062  nquark_total[iflav] + excess_quark[0][iflav] + excess_quark[1][iflav];
1063  /* Therefore, nquark_final should not be negative.
1064  * negative nquark_final means that it will not be possible to
1065  * find a constituent to change the flavor. */
1066  bool enough_quark = nquark_final >= 0;
1067  // If that is the case, excess of constituents will be modified
1068  if (!enough_quark) {
1069  logg[LPythia].debug(" not enough constituents with flavor ", iflav + 1,
1070  " : try to modify excess of constituents.");
1071  for (int ic = 0; ic < std::abs(nquark_final); ic++) {
1072  /* Since each incoming hadron has its own count of the excess,
1073  * it is necessary to find which one is problematic. */
1074  int ih_mod = -1;
1075  if (excess_quark[0][iflav] < 0) {
1076  ih_mod = 0;
1077  } else {
1078  ih_mod = 1;
1079  }
1080  /* Increase the excess of both quark and antiquark
1081  * with corresponding flavor (iflav + 1) by 1.
1082  * This is for conservation of the net quark number. */
1083  excess_quark[ih_mod][iflav] += 1;
1084  excess_antiq[ih_mod][iflav] += 1;
1085 
1086  /* Since incoming hadrons are mapped onto ones with
1087  * the same baryon number (or quark number),
1088  * summation of the excesses over all flavors should be zero.
1089  * Therefore, we need to find another flavor which has
1090  * a positive excess and subtract by 1. */
1091  for (int jflav = 0; jflav < 5; jflav++) {
1092  // another flavor with positive excess of constituents
1093  if (jflav != iflav && excess_quark[ih_mod][jflav] > 0) {
1094  /* Decrease the excess of both quark and antiquark
1095  * with corresponding flavor (jflav + 1) by 1. */
1096  excess_quark[ih_mod][jflav] -= 1;
1097  excess_antiq[ih_mod][jflav] -= 1;
1098  /* We only need to find one (another) flavor to subtract.
1099  * No more! */
1100  break;
1101  }
1102  }
1103  }
1104  }
1105  }
1106 }
1107 
1109  Pythia8::Event &event_intermediate,
1110  std::array<std::array<int, 5>, 2> &excess_quark,
1111  std::array<std::array<int, 5>, 2> &excess_antiq) {
1112  Pythia8::Vec4 pSum = event_intermediate[0].p();
1113  const double energy_init = pSum.e();
1114  logg[LPythia].debug(" initial total energy [GeV] : ", energy_init);
1115 
1116  // Total number of quarks and antiquarks, respectively.
1117  std::array<int, 5> nquark_total;
1118  std::array<int, 5> nantiq_total;
1119 
1120  /* Split a gluon into qqbar if we do not have enough constituents
1121  * to be converted in the system. */
1122  bool split_for_quark = splitting_gluon_qqbar(
1123  event_intermediate, nquark_total, nantiq_total, true, excess_quark);
1124  bool split_for_antiq = splitting_gluon_qqbar(
1125  event_intermediate, nquark_total, nantiq_total, false, excess_antiq);
1126 
1127  /* Modify excess_quark and excess_antiq if we do not have enough constituents
1128  * to be converted in the system. */
1129  if (!split_for_quark || !split_for_antiq) {
1130  rearrange_excess(nquark_total, excess_quark, excess_antiq);
1131  rearrange_excess(nantiq_total, excess_antiq, excess_quark);
1132  }
1133 
1134  // Final check if there are enough constituents.
1135  for (int iflav = 0; iflav < 5; iflav++) {
1136  if (nquark_total[iflav] + excess_quark[0][iflav] + excess_quark[1][iflav] <
1137  0) {
1138  logg[LPythia].debug("Not enough quark constituents of flavor ",
1139  iflav + 1);
1140  return false;
1141  }
1142 
1143  if (nantiq_total[iflav] + excess_antiq[0][iflav] + excess_antiq[1][iflav] <
1144  0) {
1145  logg[LPythia].debug("Not enough antiquark constituents of flavor ",
1146  -(iflav + 1));
1147  return false;
1148  }
1149  }
1150 
1151  for (int ih = 0; ih < 2; ih++) {
1152  logg[LPythia].debug(" initial excess_quark[", ih, "] = (",
1153  excess_quark[ih][0], ", ", excess_quark[ih][1], ", ",
1154  excess_quark[ih][2], ", ", excess_quark[ih][3], ", ",
1155  excess_quark[ih][4], ")");
1156  logg[LPythia].debug(" initial excess_antiq[", ih, "] = (",
1157  excess_antiq[ih][0], ", ", excess_antiq[ih][1], ", ",
1158  excess_antiq[ih][2], ", ", excess_antiq[ih][3], ", ",
1159  excess_antiq[ih][4], ")");
1160  }
1161 
1162  bool recovered_quarks = false;
1163  while (!recovered_quarks) {
1164  /* Flavor conversion begins with the most forward and backward parton
1165  * respectively for incoming_particles_[0] and incoming_particles_[1]. */
1166  std::array<bool, 2> find_forward = {true, false};
1167  const std::array<int, 5> excess_null = {0, 0, 0, 0, 0};
1168  std::array<int, 5> excess_total = excess_null;
1169 
1170  for (int ih = 0; ih < 2; ih++) { // loop over incoming hadrons
1171  int nfrag = event_intermediate.size();
1172  for (int np_end = 0; np_end < nfrag - 1; np_end++) { // constituent loop
1173  /* select the np_end-th most forward or backward parton and
1174  * change its specie.
1175  * np_end = 0 corresponds to the most forward,
1176  * np_end = 1 corresponds to the second most forward and so on. */
1177  int iforward =
1178  get_index_forward(find_forward[ih], np_end, event_intermediate);
1179  pSum -= event_intermediate[iforward].p();
1180 
1181  if (event_intermediate[iforward].id() > 0) { // quark and diquark
1182  replace_constituent(event_intermediate[iforward], excess_quark[ih]);
1183  logg[LPythia].debug(
1184  " excess_quark[", ih, "] = (", excess_quark[ih][0], ", ",
1185  excess_quark[ih][1], ", ", excess_quark[ih][2], ", ",
1186  excess_quark[ih][3], ", ", excess_quark[ih][4], ")");
1187  } else { // antiquark and anti-diquark
1188  replace_constituent(event_intermediate[iforward], excess_antiq[ih]);
1189  logg[LPythia].debug(
1190  " excess_antiq[", ih, "] = (", excess_antiq[ih][0], ", ",
1191  excess_antiq[ih][1], ", ", excess_antiq[ih][2], ", ",
1192  excess_antiq[ih][3], ", ", excess_antiq[ih][4], ")");
1193  }
1194 
1195  const int pdgid = event_intermediate[iforward].id();
1196  Pythia8::Vec4 pquark = event_intermediate[iforward].p();
1197  const double mass = pythia_hadron_->particleData.m0(pdgid);
1198 
1199  const int status = event_intermediate[iforward].status();
1200  const int color = event_intermediate[iforward].col();
1201  const int anticolor = event_intermediate[iforward].acol();
1202 
1203  pSum += pquark;
1204  event_intermediate.append(pdgid, status, color, anticolor, pquark,
1205  mass);
1206 
1207  event_intermediate.remove(iforward, iforward);
1208  /* Now the last np_end + 1 entries in event_intermediate
1209  * are np_end + 1 most forward (or backward) partons. */
1210  }
1211 
1212  // Compute the excess of net quark numbers.
1213  for (int j = 0; j < 5; j++) {
1214  excess_total[j] += (excess_quark[ih][j] - excess_antiq[ih][j]);
1215  }
1216  }
1217 
1218  /* If there is no excess of net quark numbers,
1219  * quark content is considered to be correct. */
1220  recovered_quarks = excess_total == excess_null;
1221  }
1222  logg[LPythia].debug(" valence quark contents of hadons are recovered.");
1223 
1224  logg[LPythia].debug(" current total energy [GeV] : ", pSum.e());
1225  /* rescale momenta of all partons by a constant factor
1226  * to conserve the total energy. */
1227  while (true) {
1228  if (std::abs(pSum.e() - energy_init) <=
1229  std::abs(really_small * energy_init)) {
1230  break;
1231  }
1232 
1233  double energy_current = pSum.e();
1234  double slope = 0.;
1235  for (int i = 1; i < event_intermediate.size(); i++) {
1236  slope += event_intermediate[i].pAbs2() / event_intermediate[i].e();
1237  }
1238 
1239  const double rescale_factor = 1. + (energy_init - energy_current) / slope;
1240  pSum = 0.;
1241  for (int i = 1; i < event_intermediate.size(); i++) {
1242  const double px = rescale_factor * event_intermediate[i].px();
1243  const double py = rescale_factor * event_intermediate[i].py();
1244  const double pz = rescale_factor * event_intermediate[i].pz();
1245  const double pabs = rescale_factor * event_intermediate[i].pAbs();
1246  const double mass = event_intermediate[i].m();
1247 
1248  event_intermediate[i].px(px);
1249  event_intermediate[i].py(py);
1250  event_intermediate[i].pz(pz);
1251  event_intermediate[i].e(std::sqrt(mass * mass + pabs * pabs));
1252  pSum += event_intermediate[i].p();
1253  }
1254  logg[LPythia].debug(" parton momenta are rescaled by factor of ",
1255  rescale_factor);
1256  }
1257 
1258  logg[LPythia].debug(" final total energy [GeV] : ", pSum.e());
1259  /* The zeroth entry of event record is supposed to have the information
1260  * on the whole system. Specify the total momentum and invariant mass. */
1261  event_intermediate[0].p(pSum);
1262  event_intermediate[0].m(pSum.mCalc());
1263 
1264  return true;
1265 }
1266 
1267 void StringProcess::compose_string_parton(bool find_forward_string,
1268  Pythia8::Event &event_intermediate,
1269  Pythia8::Event &event_hadronize) {
1270  Pythia8::Vec4 pSum = 0.;
1271  event_hadronize.reset();
1272 
1273  // select the most forward or backward parton.
1274  int iforward = get_index_forward(find_forward_string, 0, event_intermediate);
1275  logg[LPythia].debug("Hard non-diff: iforward = ", iforward, "(",
1276  event_intermediate[iforward].id(), ")");
1277 
1278  pSum += event_intermediate[iforward].p();
1279  event_hadronize.append(event_intermediate[iforward]);
1280 
1281  int col_to_find = event_intermediate[iforward].acol();
1282  int acol_to_find = event_intermediate[iforward].col();
1283  event_intermediate.remove(iforward, iforward);
1284  logg[LPythia].debug("Hard non-diff: event_intermediate reduces in size to ",
1285  event_intermediate.size());
1286 
1287  // trace color and anti-color indices and find corresponding partons.
1288  while (col_to_find != 0 || acol_to_find != 0) {
1289  logg[LPythia].debug(" col_to_find = ", col_to_find,
1290  ", acol_to_find = ", acol_to_find);
1291 
1292  int ifound = -1;
1293  for (int i = 1; i < event_intermediate.size(); i++) {
1294  const int pdgid = event_intermediate[i].id();
1295  bool found_col =
1296  col_to_find != 0 && col_to_find == event_intermediate[i].col();
1297  bool found_acol =
1298  acol_to_find != 0 && acol_to_find == event_intermediate[i].acol();
1299  if (found_col) {
1300  logg[LPythia].debug(" col_to_find ", col_to_find, " from i ", i, "(",
1301  pdgid, ") found");
1302  }
1303  if (found_acol) {
1304  logg[LPythia].debug(" acol_to_find ", acol_to_find, " from i ", i, "(",
1305  pdgid, ") found");
1306  }
1307 
1308  if (found_col && !found_acol) {
1309  ifound = i;
1310  col_to_find = event_intermediate[i].acol();
1311  break;
1312  } else if (!found_col && found_acol) {
1313  ifound = i;
1314  acol_to_find = event_intermediate[i].col();
1315  break;
1316  } else if (found_col && found_acol) {
1317  ifound = i;
1318  col_to_find = 0;
1319  acol_to_find = 0;
1320  break;
1321  }
1322  }
1323 
1324  if (ifound < 0) {
1325  event_intermediate.list();
1326  event_intermediate.listJunctions();
1327  event_hadronize.list();
1328  event_hadronize.listJunctions();
1329  if (col_to_find != 0) {
1330  logg[LPythia].error("No parton with col = ", col_to_find);
1331  }
1332  if (acol_to_find != 0) {
1333  logg[LPythia].error("No parton with acol = ", acol_to_find);
1334  }
1335  throw std::runtime_error("Hard string could not be identified.");
1336  } else {
1337  pSum += event_intermediate[ifound].p();
1338  // add a parton to the new event record.
1339  event_hadronize.append(event_intermediate[ifound]);
1340  // then remove from the original event record.
1341  event_intermediate.remove(ifound, ifound);
1342  logg[LPythia].debug(
1343  "Hard non-diff: event_intermediate reduces in size to ",
1344  event_intermediate.size());
1345  }
1346  }
1347 
1348  /* The zeroth entry of event record is supposed to have the information
1349  * on the whole system. Specify the total momentum and invariant mass. */
1350  event_hadronize[0].p(pSum);
1351  event_hadronize[0].m(pSum.mCalc());
1352 }
1353 
1354 void StringProcess::compose_string_junction(bool &find_forward_string,
1355  Pythia8::Event &event_intermediate,
1356  Pythia8::Event &event_hadronize) {
1357  event_hadronize.reset();
1358 
1359  /* Move the first junction to the event record for hadronization
1360  * and specify color or anti-color indices to be found.
1361  * If junction kind is an odd number, it connects three quarks
1362  * to make a color-neutral baryonic configuration.
1363  * Otherwise, it connects three antiquarks
1364  * to make a color-neutral anti-baryonic configuration. */
1365  const int kind = event_intermediate.kindJunction(0);
1366  bool sign_color = kind % 2 == 1;
1367  std::vector<int> col; // color or anti-color indices of the junction legs
1368  for (int j = 0; j < 3; j++) {
1369  col.push_back(event_intermediate.colJunction(0, j));
1370  }
1371  event_hadronize.appendJunction(kind, col[0], col[1], col[2]);
1372  event_intermediate.eraseJunction(0);
1373  logg[LPythia].debug("junction (", col[0], ", ", col[1], ", ", col[2],
1374  ") with kind ", kind, " will be handled.");
1375 
1376  bool found_string = false;
1377  while (!found_string) {
1378  // trace color or anti-color indices and find corresponding partons.
1379  find_junction_leg(sign_color, col, event_intermediate, event_hadronize);
1380  found_string = true;
1381  for (unsigned int j = 0; j < col.size(); j++) {
1382  found_string = found_string && col[j] == 0;
1383  }
1384  if (!found_string) {
1385  /* if there is any leg which is not closed with parton,
1386  * look over junctions and find connected ones. */
1387  logg[LPythia].debug(" still has leg(s) unfinished.");
1388  sign_color = !sign_color;
1389  std::vector<int> junction_to_move;
1390  for (int i = 0; i < event_intermediate.sizeJunction(); i++) {
1391  const int kind_new = event_intermediate.kindJunction(i);
1392  /* If the original junction is associated with positive baryon number,
1393  * it looks for anti-junctions whose legs are connected with
1394  * anti-quarks (anti-colors in general). */
1395  if (sign_color != (kind_new % 2 == 1)) {
1396  continue;
1397  }
1398 
1399  std::array<int, 3> col_new;
1400  for (int k = 0; k < 3; k++) {
1401  col_new[k] = event_intermediate.colJunction(i, k);
1402  }
1403 
1404  int n_legs_connected = 0;
1405  // loop over remaining legs
1406  for (unsigned int j = 0; j < col.size(); j++) {
1407  if (col[j] == 0) {
1408  continue;
1409  }
1410  for (int k = 0; k < 3; k++) {
1411  if (col[j] == col_new[k]) {
1412  n_legs_connected += 1;
1413  col[j] = 0;
1414  col_new[k] = 0;
1415  }
1416  }
1417  }
1418 
1419  // specify which junction is connected to the original one.
1420  if (n_legs_connected > 0) {
1421  for (int k = 0; k < 3; k++) {
1422  if (col_new[k] != 0) {
1423  col.push_back(col_new[k]);
1424  }
1425  }
1426  logg[LPythia].debug(" junction ", i, " (",
1427  event_intermediate.colJunction(i, 0), ", ",
1428  event_intermediate.colJunction(i, 1), ", ",
1429  event_intermediate.colJunction(i, 2),
1430  ") with kind ", kind_new, " will be added.");
1431  junction_to_move.push_back(i);
1432  }
1433  }
1434 
1435  /* If there is any connected junction,
1436  * move it to the event record for hadronization. */
1437  for (unsigned int i = 0; i < junction_to_move.size(); i++) {
1438  unsigned int imove = junction_to_move[i] - i;
1439  const int kind_add = event_intermediate.kindJunction(imove);
1440  std::array<int, 3> col_add;
1441  for (int k = 0; k < 3; k++) {
1442  col_add[k] = event_intermediate.colJunction(imove, k);
1443  }
1444  // add a junction to the new event record.
1445  event_hadronize.appendJunction(kind_add, col_add[0], col_add[1],
1446  col_add[2]);
1447  // then remove from the original event record.
1448  event_intermediate.eraseJunction(imove);
1449  }
1450  }
1451  }
1452 
1453  Pythia8::Vec4 pSum = event_hadronize[0].p();
1454  find_forward_string = pSum.pz() > 0.;
1455 }
1456 
1457 void StringProcess::find_junction_leg(bool sign_color, std::vector<int> &col,
1458  Pythia8::Event &event_intermediate,
1459  Pythia8::Event &event_hadronize) {
1460  Pythia8::Vec4 pSum = event_hadronize[0].p();
1461  for (unsigned int j = 0; j < col.size(); j++) {
1462  if (col[j] == 0) {
1463  continue;
1464  }
1465  bool found_leg = false;
1466  while (!found_leg) {
1467  int ifound = -1;
1468  for (int i = 1; i < event_intermediate.size(); i++) {
1469  const int pdgid = event_intermediate[i].id();
1470  if (sign_color && col[j] == event_intermediate[i].col()) {
1471  logg[LPythia].debug(" col[", j, "] = ", col[j], " from i ", i, "(",
1472  pdgid, ") found");
1473  ifound = i;
1474  col[j] = event_intermediate[i].acol();
1475  break;
1476  } else if (!sign_color && col[j] == event_intermediate[i].acol()) {
1477  logg[LPythia].debug(" acol[", j, "] = ", col[j], " from i ", i, "(",
1478  pdgid, ") found");
1479  ifound = i;
1480  col[j] = event_intermediate[i].col();
1481  break;
1482  }
1483  }
1484 
1485  if (ifound < 0) {
1486  found_leg = true;
1487  if (event_intermediate.sizeJunction() == 0) {
1488  event_intermediate.list();
1489  event_intermediate.listJunctions();
1490  event_hadronize.list();
1491  event_hadronize.listJunctions();
1492  logg[LPythia].error("No parton with col = ", col[j],
1493  " connected with junction leg ", j);
1494  throw std::runtime_error("Hard string could not be identified.");
1495  }
1496  } else {
1497  pSum += event_intermediate[ifound].p();
1498  // add a parton to the new event record.
1499  event_hadronize.append(event_intermediate[ifound]);
1500  // then remove from the original event record.
1501  event_intermediate.remove(ifound, ifound);
1502  logg[LPythia].debug(
1503  "Hard non-diff: event_intermediate reduces in size to ",
1504  event_intermediate.size());
1505  if (col[j] == 0) {
1506  found_leg = true;
1507  }
1508  }
1509  }
1510  }
1511 
1512  /* The zeroth entry of event record is supposed to have the information
1513  * on the whole system. Specify the total momentum and invariant mass. */
1514  event_hadronize[0].p(pSum);
1515  event_hadronize[0].m(pSum.mCalc());
1516 }
1517 
1518 // baryon-antibaryon annihilation
1520  const std::array<FourVector, 2> ustrcom = {FourVector(1., 0., 0., 0.),
1521  FourVector(1., 0., 0., 0.)};
1522 
1523  NpartFinal_ = 0;
1524  NpartString_[0] = 0;
1525  NpartString_[1] = 0;
1526  final_state_.clear();
1527 
1528  logg[LPythia].debug("Annihilation occurs between ", PDGcodes_[0], "+",
1529  PDGcodes_[1], " at CM energy [GeV] ", sqrtsAB_);
1530 
1531  // check if the initial state is baryon-antibaryon pair.
1532  PdgCode baryon = PDGcodes_[0], antibaryon = PDGcodes_[1];
1533  if (baryon.baryon_number() == -1) {
1534  std::swap(baryon, antibaryon);
1535  }
1536  if (baryon.baryon_number() != 1 || antibaryon.baryon_number() != -1) {
1537  throw std::invalid_argument("Expected baryon-antibaryon pair.");
1538  }
1539 
1540  // Count how many qqbar combinations are possible for each quark type
1541  constexpr int n_q_types = 5; // u, d, s, c, b
1542  std::vector<int> qcount_bar, qcount_antibar;
1543  std::vector<int> n_combinations;
1544  bool no_combinations = true;
1545  for (int i = 0; i < n_q_types; i++) {
1546  qcount_bar.push_back(baryon.net_quark_number(i + 1));
1547  qcount_antibar.push_back(-antibaryon.net_quark_number(i + 1));
1548  const int n_i = qcount_bar[i] * qcount_antibar[i];
1549  n_combinations.push_back(n_i);
1550  if (n_i > 0) {
1551  no_combinations = false;
1552  }
1553  }
1554 
1555  /* if it is a BBbar pair but there is no qqbar pair to annihilate,
1556  * nothing happens */
1557  if (no_combinations) {
1558  for (int i = 0; i < 2; i++) {
1559  NpartString_[i] = 1;
1560  ParticleData new_particle(ParticleType::find(PDGcodes_[i]));
1561  new_particle.set_4momentum(pcom_[i]);
1562  new_particle.set_cross_section_scaling_factor(1.);
1563  new_particle.set_formation_time(time_collision_);
1564  final_state_.push_back(new_particle);
1565  }
1567  return true;
1568  }
1569 
1570  // Select qqbar pair to annihilate and remove it away
1571  auto discrete_distr = random::discrete_dist<int>(n_combinations);
1572  const int q_annihilate = discrete_distr() + 1;
1573  qcount_bar[q_annihilate - 1]--;
1574  qcount_antibar[q_annihilate - 1]--;
1575 
1576  // Get the remaining quarks and antiquarks
1577  std::vector<int> remaining_quarks, remaining_antiquarks;
1578  for (int i = 0; i < n_q_types; i++) {
1579  for (int j = 0; j < qcount_bar[i]; j++) {
1580  remaining_quarks.push_back(i + 1);
1581  }
1582  for (int j = 0; j < qcount_antibar[i]; j++) {
1583  remaining_antiquarks.push_back(-(i + 1));
1584  }
1585  }
1586  assert(remaining_quarks.size() == 2);
1587  assert(remaining_antiquarks.size() == 2);
1588 
1589  const std::array<double, 2> mstr = {0.5 * sqrtsAB_, 0.5 * sqrtsAB_};
1590 
1591  // randomly select two quark-antiquark pairs
1592  if (random::uniform_int(0, 1) == 0) {
1593  std::swap(remaining_quarks[0], remaining_quarks[1]);
1594  }
1595  if (random::uniform_int(0, 1) == 0) {
1596  std::swap(remaining_antiquarks[0], remaining_antiquarks[1]);
1597  }
1598  // Make sure it satisfies kinematical threshold constraint
1599  bool kin_threshold_satisfied = true;
1600  for (int i = 0; i < 2; i++) {
1601  const double mstr_min =
1602  pythia_hadron_->particleData.m0(remaining_quarks[i]) +
1603  pythia_hadron_->particleData.m0(remaining_antiquarks[i]);
1604  if (mstr_min > mstr[i]) {
1605  kin_threshold_satisfied = false;
1606  }
1607  }
1608  if (!kin_threshold_satisfied) {
1609  return false;
1610  }
1611  // Fragment two strings
1612  for (int i = 0; i < 2; i++) {
1613  ParticleList new_intermediate_particles;
1614 
1615  ThreeVector evec = pcom_[i].threevec() / pcom_[i].threevec().abs();
1616  const int nfrag =
1617  fragment_string(remaining_quarks[i], remaining_antiquarks[i], mstr[i],
1618  evec, true, false, new_intermediate_particles);
1619  if (nfrag <= 0) {
1620  NpartString_[i] = 0;
1621  return false;
1622  }
1623  NpartString_[i] =
1624  append_final_state(new_intermediate_particles, ustrcom[i], evec);
1625  }
1627  return true;
1628 }
1629 
1631  ThreeVector &evec_polar, std::array<ThreeVector, 3> &evec_basis) {
1632  assert(std::fabs(evec_polar.sqr() - 1.) < really_small);
1633 
1634  if (std::abs(evec_polar.x3()) < (1. - 1.0e-8)) {
1635  double ex, ey, et;
1636  double theta, phi;
1637 
1638  // evec_basis[0] is set to be longitudinal direction
1639  evec_basis[0] = evec_polar;
1640 
1641  theta = std::acos(evec_basis[0].x3());
1642 
1643  ex = evec_basis[0].x1();
1644  ey = evec_basis[0].x2();
1645  et = std::sqrt(ex * ex + ey * ey);
1646  if (ey > 0.) {
1647  phi = std::acos(ex / et);
1648  } else {
1649  phi = -std::acos(ex / et);
1650  }
1651 
1652  /* The transverse plane is spanned
1653  * by evec_basis[1] and evec_basis[2]. */
1654  evec_basis[1].set_x1(std::cos(theta) * std::cos(phi));
1655  evec_basis[1].set_x2(std::cos(theta) * std::sin(phi));
1656  evec_basis[1].set_x3(-std::sin(theta));
1657 
1658  evec_basis[2].set_x1(-std::sin(phi));
1659  evec_basis[2].set_x2(std::cos(phi));
1660  evec_basis[2].set_x3(0.);
1661  } else {
1662  // if evec_polar is very close to the z axis
1663  if (evec_polar.x3() > 0.) {
1664  evec_basis[1] = ThreeVector(1., 0., 0.);
1665  evec_basis[2] = ThreeVector(0., 1., 0.);
1666  evec_basis[0] = ThreeVector(0., 0., 1.);
1667  } else {
1668  evec_basis[1] = ThreeVector(0., 1., 0.);
1669  evec_basis[2] = ThreeVector(1., 0., 0.);
1670  evec_basis[0] = ThreeVector(0., 0., -1.);
1671  }
1672  }
1673 
1674  assert(std::fabs(evec_basis[1] * evec_basis[2]) < really_small);
1675  assert(std::fabs(evec_basis[2] * evec_basis[0]) < really_small);
1676  assert(std::fabs(evec_basis[0] * evec_basis[1]) < really_small);
1677 }
1678 
1680  PPosA_ = (pcom_[0].x0() + evecBasisAB_[0] * pcom_[0].threevec()) * M_SQRT1_2;
1681  PNegA_ = (pcom_[0].x0() - evecBasisAB_[0] * pcom_[0].threevec()) * M_SQRT1_2;
1682  PPosB_ = (pcom_[1].x0() + evecBasisAB_[0] * pcom_[1].threevec()) * M_SQRT1_2;
1683  PNegB_ = (pcom_[1].x0() - evecBasisAB_[0] * pcom_[1].threevec()) * M_SQRT1_2;
1684 }
1685 
1686 void StringProcess::quarks_from_diquark(int diquark, int &q1, int &q2,
1687  int &deg_spin) {
1688  // The 4-digit pdg id should be diquark.
1689  assert((std::abs(diquark) > 1000) && (std::abs(diquark) < 5510) &&
1690  (std::abs(diquark) % 100 < 10));
1691 
1692  // The fourth digit corresponds to the spin degeneracy.
1693  deg_spin = std::abs(diquark) % 10;
1694  // Diquark (anti-diquark) is decomposed into two quarks (antiquarks).
1695  const int sign_anti = diquark > 0 ? 1 : -1;
1696 
1697  // Obtain two quarks (or antiquarks) from the first and second digit.
1698  q1 = sign_anti * (std::abs(diquark) - (std::abs(diquark) % 1000)) / 1000;
1699  q2 = sign_anti * (std::abs(diquark) % 1000 - deg_spin) / 100;
1700 }
1701 
1703  assert((q1 > 0 && q2 > 0) || (q1 < 0 && q2 < 0));
1704  if (std::abs(q1) < std::abs(q2)) {
1705  std::swap(q1, q2);
1706  }
1707  int diquark = std::abs(q1 * 1000 + q2 * 100);
1708  /* Adding spin degeneracy = 2S+1. For identical quarks spin cannot be 0
1709  * because of Pauli exclusion principle, so spin 1 is assumed. Otherwise
1710  * S = 0 with probability 1/4 and S = 1 with probability 3/4. */
1711  diquark += (q1 != q2 && random::uniform_int(0, 3) == 0) ? 1 : 3;
1712  return (q1 < 0) ? -diquark : diquark;
1713 }
1714 
1715 void StringProcess::make_string_ends(const PdgCode &pdg, int &idq1, int &idq2,
1716  double xi) {
1717  std::array<int, 3> quarks = pdg.quark_content();
1718  if (pdg.is_nucleon()) {
1719  // protons and neutrons treated seperately since single quarks is at a
1720  // different position in the PDG code
1721  if (pdg.charge() == 0) { // (anti)neutron
1722  if (random::uniform(0., 1.) < xi) {
1723  idq1 = quarks[0];
1724  idq2 = diquark_from_quarks(quarks[1], quarks[2]);
1725  } else {
1726  idq1 = quarks[1];
1727  idq2 = diquark_from_quarks(quarks[0], quarks[2]);
1728  }
1729  } else { // (anti)proton
1730  if (random::uniform(0., 1.) < xi) {
1731  idq1 = quarks[2];
1732  idq2 = diquark_from_quarks(quarks[0], quarks[1]);
1733  } else {
1734  idq1 = quarks[0];
1735  idq2 = diquark_from_quarks(quarks[1], quarks[2]);
1736  }
1737  }
1738  } else {
1739  if (pdg.is_meson()) {
1740  idq1 = quarks[1];
1741  idq2 = quarks[2];
1742  /* Some mesons with PDG id 11X are actually mixed state of uubar and
1743  * ddbar. have a random selection whether we have uubar or ddbar in this
1744  * case. */
1745  if (idq1 == 1 && idq2 == -1 && random::uniform_int(0, 1) == 0) {
1746  idq1 = 2;
1747  idq2 = -2;
1748  }
1749  } else {
1750  assert(pdg.is_baryon());
1751  // Get random quark to position 0
1752  std::swap(quarks[random::uniform_int(0, 2)], quarks[0]);
1753  idq1 = quarks[0];
1754  idq2 = diquark_from_quarks(quarks[1], quarks[2]);
1755  }
1756  }
1757  // Fulfil the convention: idq1 should be quark or anti-diquark
1758  if (idq1 < 0) {
1759  std::swap(idq1, idq2);
1760  }
1761 }
1762 
1763 int StringProcess::fragment_string(int idq1, int idq2, double mString,
1764  ThreeVector &evecLong, bool flip_string_ends,
1765  bool separate_fragment_baryon,
1766  ParticleList &intermediate_particles) {
1767  pythia_hadron_->event.reset();
1768  intermediate_particles.clear();
1769 
1770  logg[LPythia].debug("initial quark content for fragment_string : ", idq1,
1771  ", ", idq2);
1772  logg[LPythia].debug("initial string mass (GeV) for fragment_string : ",
1773  mString);
1774  // PDG id of quark constituents of string ends
1775  std::array<int, 2> idqIn;
1776  idqIn[0] = idq1;
1777  idqIn[1] = idq2;
1778 
1779  int bstring = 0;
1780  // constituent masses of the string
1781  std::array<double, 2> m_const;
1782 
1783  for (int i = 0; i < 2; i++) {
1784  // evaluate total baryon number of the string times 3
1785  bstring += pythia_hadron_->particleData.baryonNumberType(idqIn[i]);
1786 
1787  m_const[i] = pythia_hadron_->particleData.m0(idqIn[i]);
1788  }
1789  logg[LPythia].debug("baryon number of string times 3 : ", bstring);
1790 
1791  if (flip_string_ends && random::uniform_int(0, 1) == 0) {
1792  /* in the case where we flip the string ends,
1793  * we need to flip the longitudinal unit vector itself
1794  * since it is set to be direction of diquark (anti-quark)
1795  * or anti-diquark. */
1796  evecLong = -evecLong;
1797  }
1798 
1799  if (m_const[0] + m_const[1] > mString) {
1800  throw std::runtime_error("String fragmentation: m1 + m2 > mString");
1801  }
1802  Pythia8::Vec4 pSum = 0.;
1803 
1804  int number_of_fragments = 0;
1805  bool do_string_fragmentation = false;
1806 
1807  /* lightcone momenta p^+ and p^- of the string
1808  * p^{\pm} is defined as (E \pm p_{longitudinal}) / sqrts{2}. */
1809  double ppos_string_new, pneg_string_new;
1810  /* transverse momentum (and magnitude) acquired
1811  * by the the string to be fragmented */
1812  double QTrx_string_new, QTry_string_new, QTrn_string_new;
1813  // transverse mass of the string to be fragmented
1814  double mTrn_string_new;
1815  // mass of the string to be fragmented
1816  double mass_string_new;
1817 
1818  /* Transverse momentum to be added to the most forward hadron
1819  * from PYTHIA fragmentation */
1820  double QTrx_add_pos, QTry_add_pos;
1821  /* Transverse momentum to be added to the most backward hadron
1822  * from PYTHIA fragmentation */
1823  double QTrx_add_neg, QTry_add_neg;
1824 
1825  /* Set those transverse momenta to be zero.
1826  * This is the case when we solely rely on the PYTHIA fragmentation
1827  * procedure without separate fragmentation function.
1828  * In the case of separate fragmentation function for the leading baryon,
1829  * appropriate values will be assigned later. */
1830  QTrx_add_pos = 0.;
1831  QTry_add_pos = 0.;
1832  QTrx_add_neg = 0.;
1833  QTry_add_neg = 0.;
1834 
1835  std::array<ThreeVector, 3> evec_basis;
1836  make_orthonormal_basis(evecLong, evec_basis);
1837 
1838  if (separate_fragment_baryon && (std::abs(bstring) == 3) &&
1839  (mString > m_const[0] + m_const[1] + 1.)) {
1840  /* A separate fragmentation function will be used to the leading baryon,
1841  * if we have a baryonic string and the corresponding option is turned on.
1842  */
1843  int n_frag_prior;
1844  /* PDG id of fragmented hadrons
1845  * before switching to the PYTHIA fragmentation */
1846  std::vector<int> pdgid_frag_prior;
1847  /* four-momenta of fragmented hadrons
1848  * before switching to the PYTHIA fragmentation */
1849  std::vector<FourVector> momentum_frag_prior;
1850 
1851  // Transverse momentum px of the forward end of the string
1852  double QTrx_string_pos;
1853  // Transverse momentum px of the backward end of the string
1854  double QTrx_string_neg;
1855  // Transverse momentum py of the forward end of the string
1856  double QTry_string_pos;
1857  // Transverse momentum py of the backward end of the string
1858  double QTry_string_neg;
1859  /* Absolute value of the transverse momentum of
1860  * the forward end of the string */
1861  double QTrn_string_pos;
1862  /* Absolute value of the transverse momentum of
1863  * the backward end of the string */
1864  double QTrn_string_neg;
1865 
1866  std::array<double, 2> m_trans;
1867 
1868  // How many times we try to fragment leading baryon.
1869  const int niter_max = 10000;
1870  bool found_leading_baryon = false;
1871  for (int iiter = 0; iiter < niter_max; iiter++) {
1872  n_frag_prior = 0;
1873  pdgid_frag_prior.clear();
1874  momentum_frag_prior.clear();
1875  int n_frag = 0;
1876  std::vector<int> pdgid_frag;
1877  std::vector<FourVector> momentum_frag;
1878  // The original string is aligned in the logitudinal direction.
1879  ppos_string_new = mString * M_SQRT1_2;
1880  pneg_string_new = mString * M_SQRT1_2;
1881  // There is no transverse momentum at the original string ends.
1882  QTrx_string_pos = 0.;
1883  QTrx_string_neg = 0.;
1884  QTrx_string_new = 0.;
1885  QTry_string_pos = 0.;
1886  QTry_string_neg = 0.;
1887  QTry_string_new = 0.;
1888  // Constituent flavor at the forward (diquark) end of the string
1889  Pythia8::FlavContainer flav_string_pos =
1890  bstring > 0 ? Pythia8::FlavContainer(idq2)
1891  : Pythia8::FlavContainer(idq1);
1892  // Constituent flavor at the backward (quark) end of the string
1893  Pythia8::FlavContainer flav_string_neg =
1894  bstring > 0 ? Pythia8::FlavContainer(idq1)
1895  : Pythia8::FlavContainer(idq2);
1896  // Whether the first baryon from the forward end is fragmented
1897  bool found_forward_baryon = false;
1898  // Whether the first hadron from the forward end is fragmented
1899  bool done_forward_end = false;
1900  /* Whether energy of the string is depleted and the string
1901  * breaks into final two hadrons. */
1902  bool energy_used_up = false;
1903  while (!found_forward_baryon && !energy_used_up) {
1904  /* Keep fragmenting hadrons until
1905  * the first baryon is fragmented from the forward (diquark) end or
1906  * energy of the string is used up. */
1907  // Randomly select the string end from which the hadron is fragmented.
1908  bool from_forward = random::uniform_int(0, 1) == 0;
1909  /* The separate fragmentation function for the leading baryon kicks in
1910  * only if the first fragmented hadron from the forward (diquark) end
1911  * is a baryon. */
1912  n_frag = fragment_off_hadron(
1913  from_forward,
1914  separate_fragment_baryon && from_forward && !done_forward_end,
1915  evec_basis, ppos_string_new, pneg_string_new, QTrx_string_pos,
1916  QTrx_string_neg, QTry_string_pos, QTry_string_neg, flav_string_pos,
1917  flav_string_neg, pdgid_frag, momentum_frag);
1918  if (n_frag == 0) {
1919  /* If it fails to fragment hadron, start over from
1920  * the initial (baryonic) string configuration. */
1921  break;
1922  } else {
1923  QTrx_string_new = QTrx_string_pos + QTrx_string_neg;
1924  QTry_string_new = QTry_string_pos + QTry_string_neg;
1925  /* Quark (antiquark) constituents of the remaining string are
1926  * different from those of the original string.
1927  * Therefore, the constituent masses have to be updated. */
1928  idqIn[0] = bstring > 0 ? flav_string_neg.id : flav_string_pos.id;
1929  idqIn[1] = bstring > 0 ? flav_string_pos.id : flav_string_neg.id;
1930  for (int i = 0; i < 2; i++) {
1931  m_const[i] = pythia_hadron_->particleData.m0(idqIn[i]);
1932  }
1933  QTrn_string_pos = std::sqrt(QTrx_string_pos * QTrx_string_pos +
1934  QTry_string_pos * QTry_string_pos);
1935  QTrn_string_neg = std::sqrt(QTrx_string_neg * QTrx_string_neg +
1936  QTry_string_neg * QTry_string_neg);
1937  if (bstring > 0) { // in the case of baryonic string
1938  /* Quark is coming from the newly produced backward qqbar pair
1939  * and therefore has transverse momentum, which is opposite to
1940  * that of the fragmented (backward) meson. */
1941  m_trans[0] = std::sqrt(m_const[0] * m_const[0] +
1942  QTrn_string_neg * QTrn_string_neg);
1943  /* Antiquark is coming from the newly produced forward qqbar pair
1944  * and therefore has transverse momentum, which is opposite to
1945  * that of the fragmented (leading) baryon. */
1946  m_trans[1] = std::sqrt(m_const[1] * m_const[1] +
1947  QTrn_string_pos * QTrn_string_pos);
1948  } else { // in the case of anti-baryonic string
1949  /* Quark is coming from the newly produced forward qqbar pair
1950  * and therefore has transverse momentum, which is opposite to
1951  * that of the fragmented (leading) antibaryon. */
1952  m_trans[0] = std::sqrt(m_const[0] * m_const[0] +
1953  QTrn_string_pos * QTrn_string_pos);
1954  /* Antiquark is coming from the newly produced backward qqbar pair
1955  * and therefore has transverse momentum, which is opposite to
1956  * that of the fragmented (backward) meson. */
1957  m_trans[1] = std::sqrt(m_const[1] * m_const[1] +
1958  QTrn_string_neg * QTrn_string_neg);
1959  }
1960  done_forward_end = done_forward_end || from_forward;
1961  found_forward_baryon =
1962  found_forward_baryon ||
1963  (from_forward &&
1964  pythia_hadron_->particleData.isBaryon(pdgid_frag[0]));
1965  }
1966  if (n_frag == 2) {
1967  energy_used_up = true;
1968  }
1969  /* Add PDG id and four-momenta of fragmented hadrons
1970  * to the list if fragmentation is successful. */
1971  n_frag_prior += n_frag;
1972  for (int i_frag = 0; i_frag < n_frag; i_frag++) {
1973  pdgid_frag_prior.push_back(pdgid_frag[i_frag]);
1974  momentum_frag_prior.push_back(momentum_frag[i_frag]);
1975  }
1976  }
1977  if (n_frag == 0) {
1978  continue;
1979  } else {
1980  if (n_frag == 1) {
1981  // Compute transverse mass and momentum of the remaining string.
1982  double mTsqr_string = 2. * ppos_string_new * pneg_string_new;
1983  mTrn_string_new = std::sqrt(mTsqr_string);
1984  QTrn_string_new = std::sqrt(QTrx_string_new * QTrx_string_new +
1985  QTry_string_new * QTry_string_new);
1986  if (mTrn_string_new < QTrn_string_new) {
1987  /* If transverse mass is lower than transverse momentum,
1988  * start over. */
1989  found_leading_baryon = false;
1990  } else {
1991  // Compute mass of the remaining string.
1992  mass_string_new =
1993  std::sqrt(mTsqr_string - QTrn_string_new * QTrn_string_new);
1994  /* Proceed only if the string mass is large enough to call
1995  * PYTHIA fragmentation routine.
1996  * Otherwise, start over. */
1997  if (mass_string_new > m_const[0] + m_const[1]) {
1998  do_string_fragmentation = true;
1999  found_leading_baryon = true;
2000  QTrx_add_pos = QTrx_string_pos;
2001  QTry_add_pos = QTry_string_pos;
2002  QTrx_add_neg = QTrx_string_neg;
2003  QTry_add_neg = QTry_string_neg;
2004  } else {
2005  found_leading_baryon = false;
2006  }
2007  }
2008  } else if (n_frag == 2) {
2009  /* If the string ended up breaking into final two hadrons,
2010  * there is no need to perform PYTHIA fragmentation. */
2011  do_string_fragmentation = false;
2012  found_leading_baryon = true;
2013  }
2014  }
2015 
2016  if (found_leading_baryon) {
2017  break;
2018  }
2019  }
2020  if (found_leading_baryon) {
2021  /* If the kinematics makes sense, add fragmented hadrons so far
2022  * to the intermediate particle list. */
2023  for (int i_frag = 0; i_frag < n_frag_prior; i_frag++) {
2024  logg[LPythia].debug("appending the the fragmented hadron ",
2025  pdgid_frag_prior[i_frag],
2026  " to the intermediate particle list.");
2027 
2028  bool found_ptype = append_intermediate_list(pdgid_frag_prior[i_frag],
2029  momentum_frag_prior[i_frag],
2030  intermediate_particles);
2031  if (!found_ptype) {
2032  logg[LPythia].error("PDG ID ", pdgid_frag_prior[i_frag],
2033  " should exist in ParticleType.");
2034  throw std::runtime_error("string fragmentation failed.");
2035  }
2036  number_of_fragments++;
2037  }
2038  } else {
2039  /* If it is not possible to find the leading baryon with appropriate
2040  * kinematics after trying many times, return failure (no hadron). */
2041  return 0;
2042  }
2043 
2044  if (do_string_fragmentation) {
2045  mTrn_string_new = std::sqrt(2. * ppos_string_new * pneg_string_new);
2046  // lightcone momentum p^+ of the quark constituents on the string ends
2047  std::array<double, 2> ppos_parton;
2048  // lightcone momentum p^- of the quark constituents on the string ends
2049  std::array<double, 2> pneg_parton;
2050 
2051  /* lightcone momenta of the string ends (quark and antiquark)
2052  * First, obtain ppos_parton[0] and ppos_parton[1]
2053  * (p^+ of quark and antiquark) by solving the following equations.
2054  * ppos_string_new = ppos_parton[0] + ppos_parton[1]
2055  * pneg_string_new = 0.5 * m_trans[0] * m_trans[0] / ppos_parton[0] +
2056  * 0.5 * m_trans[1] * m_trans[1] / ppos_parton[1] */
2057  const double pb_const =
2058  (mTrn_string_new * mTrn_string_new + m_trans[0] * m_trans[0] -
2059  m_trans[1] * m_trans[1]) /
2060  (4. * pneg_string_new);
2061  const double pc_const =
2062  0.5 * m_trans[0] * m_trans[0] * ppos_string_new / pneg_string_new;
2063  ppos_parton[0] = pb_const + (bstring > 0 ? -1. : 1.) *
2064  std::sqrt(pb_const * pb_const - pc_const);
2065  ppos_parton[1] = ppos_string_new - ppos_parton[0];
2066  /* Then, compute pneg_parton[0] and pneg_parton[1]
2067  * (p^- of quark and antiquark) from the dispersion relation.
2068  * 2 p^+ p^- = m_transverse^2 */
2069  for (int i = 0; i < 2; i++) {
2070  pneg_parton[i] = 0.5 * m_trans[i] * m_trans[i] / ppos_parton[i];
2071  }
2072 
2073  const int status = 1;
2074  int color, anticolor;
2075  ThreeVector three_mom;
2076  ThreeVector transverse_mom;
2077  Pythia8::Vec4 pquark;
2078 
2079  // quark end of the remaining (mesonic) string
2080  color = 1;
2081  anticolor = 0;
2082  /* In the case of baryonic string,
2083  * Quark is coming from the backward end of the remaining string.
2084  * Transverse momentum of the backward end is subtracted
2085  * at this point to keep the remaining string aligned in
2086  * the original longitudinal direction.
2087  * It will be added to the most backward hadron from
2088  * PYTHIA fragmentation.
2089  * In the case of anti-baryonic string,
2090  * Quark is coming from the forward end of the remaining string.
2091  * Transverse momentum of the forward end is subtracted
2092  * at this point to keep the remaining string aligned in
2093  * the original longitudinal direction.
2094  * It will be added to the most forward hadron from
2095  * PYTHIA fragmentation. */
2096  transverse_mom =
2097  bstring > 0 ? evec_basis[1] * (QTrx_string_neg - QTrx_add_neg) +
2098  evec_basis[2] * (QTry_string_neg - QTry_add_neg)
2099  : evec_basis[1] * (QTrx_string_pos - QTrx_add_pos) +
2100  evec_basis[2] * (QTry_string_pos - QTry_add_pos);
2101  three_mom =
2102  evec_basis[0] * (ppos_parton[0] - pneg_parton[0]) * M_SQRT1_2 +
2103  transverse_mom;
2104  const double E_quark =
2105  std::sqrt(m_const[0] * m_const[0] + three_mom.sqr());
2106  pquark = set_Vec4(E_quark, three_mom);
2107  pSum += pquark;
2108  pythia_hadron_->event.append(idqIn[0], status, color, anticolor, pquark,
2109  m_const[0]);
2110 
2111  // antiquark end of the remaining (mesonic) string
2112  color = 0;
2113  anticolor = 1;
2114  /* In the case of baryonic string,
2115  * Antiquark is coming from the forward end of the remaining string.
2116  * Transverse momentum of the forward end is subtracted
2117  * at this point to keep the remaining string aligned in
2118  * the original longitudinal direction.
2119  * It will be added to the most forward hadron from
2120  * PYTHIA fragmentation.
2121  * In the case of anti-baryonic string,
2122  * Antiquark is coming from the backward end of the remaining string.
2123  * Transverse momentum of the backward end is subtracted
2124  * at this point to keep the remaining string aligned in
2125  * the original longitudinal direction.
2126  * It will be added to the most backward hadron from
2127  * PYTHIA fragmentation. */
2128  transverse_mom =
2129  bstring > 0 ? evec_basis[1] * (QTrx_string_pos - QTrx_add_pos) +
2130  evec_basis[2] * (QTry_string_pos - QTry_add_pos)
2131  : evec_basis[1] * (QTrx_string_neg - QTrx_add_neg) +
2132  evec_basis[2] * (QTry_string_neg - QTry_add_neg);
2133  three_mom =
2134  evec_basis[0] * (ppos_parton[1] - pneg_parton[1]) * M_SQRT1_2 +
2135  transverse_mom;
2136  const double E_antiq =
2137  std::sqrt(m_const[1] * m_const[1] + three_mom.sqr());
2138  pquark = set_Vec4(E_antiq, three_mom);
2139  pSum += pquark;
2140  pythia_hadron_->event.append(idqIn[1], status, color, anticolor, pquark,
2141  m_const[1]);
2142  }
2143  } else {
2144  do_string_fragmentation = true;
2145 
2146  ppos_string_new = mString * M_SQRT1_2;
2147  pneg_string_new = mString * M_SQRT1_2;
2148  QTrx_string_new = 0.;
2149  QTry_string_new = 0.;
2150  QTrn_string_new = 0.;
2151  mTrn_string_new = mString;
2152  mass_string_new = mString;
2153 
2154  /* diquark (anti-quark) with PDG id idq2 is going in the direction of
2155  * evecLong.
2156  * quark with PDG id idq1 is going in the direction opposite to evecLong. */
2157  double sign_direction = 1.;
2158  if (bstring == -3) { // anti-baryonic string
2159  /* anti-diquark with PDG id idq1 is going in the direction of evecLong.
2160  * anti-quark with PDG id idq2 is going in the direction
2161  * opposite to evecLong. */
2162  sign_direction = -1;
2163  }
2164 
2165  // evaluate momenta of quarks
2166  const double pCMquark = pCM(mString, m_const[0], m_const[1]);
2167  const double E1 = std::sqrt(m_const[0] * m_const[0] + pCMquark * pCMquark);
2168  const double E2 = std::sqrt(m_const[1] * m_const[1] + pCMquark * pCMquark);
2169 
2170  ThreeVector direction = sign_direction * evecLong;
2171 
2172  // For status and (anti)color see \iref{Sjostrand:2007gs}.
2173  const int status1 = 1, color1 = 1, anticolor1 = 0;
2174  Pythia8::Vec4 pquark = set_Vec4(E1, -direction * pCMquark);
2175  pSum += pquark;
2176  pythia_hadron_->event.append(idqIn[0], status1, color1, anticolor1, pquark,
2177  m_const[0]);
2178 
2179  const int status2 = 1, color2 = 0, anticolor2 = 1;
2180  pquark = set_Vec4(E2, direction * pCMquark);
2181  pSum += pquark;
2182  pythia_hadron_->event.append(idqIn[1], status2, color2, anticolor2, pquark,
2183  m_const[1]);
2184  }
2185 
2186  if (do_string_fragmentation) {
2187  logg[LPythia].debug("fragmenting a string with ", idqIn[0], ", ", idqIn[1]);
2188  // implement PYTHIA fragmentation
2189  pythia_hadron_->event[0].p(pSum);
2190  pythia_hadron_->event[0].m(pSum.mCalc());
2191  bool successful_hadronization = pythia_hadron_->next();
2192  // update_info();
2193  if (!successful_hadronization) {
2194  return 0;
2195  }
2196 
2197  /* Add transverse momenta of string ends to the most forward and
2198  * backward hadrons from PYTHIA fragmentation. */
2199  bool successful_kinematics = remake_kinematics_fragments(
2200  pythia_hadron_->event, evec_basis, ppos_string_new, pneg_string_new,
2201  QTrx_string_new, QTry_string_new, QTrx_add_pos, QTry_add_pos,
2202  QTrx_add_neg, QTry_add_neg);
2203  if (!successful_kinematics) {
2204  return 0;
2205  }
2206 
2207  for (int ipyth = 0; ipyth < pythia_hadron_->event.size(); ipyth++) {
2208  if (!pythia_hadron_->event[ipyth].isFinal()) {
2209  continue;
2210  }
2211  int pythia_id = pythia_hadron_->event[ipyth].id();
2212  /* K_short and K_long need are converted to K0
2213  * since SMASH only knows K0 */
2214  convert_KaonLS(pythia_id);
2215  FourVector momentum(
2216  pythia_hadron_->event[ipyth].e(), pythia_hadron_->event[ipyth].px(),
2217  pythia_hadron_->event[ipyth].py(), pythia_hadron_->event[ipyth].pz());
2218  logg[LPythia].debug("appending the fragmented hadron ", pythia_id,
2219  " to the intermediate particle list.");
2220  bool found_ptype =
2221  append_intermediate_list(pythia_id, momentum, intermediate_particles);
2222  if (!found_ptype) {
2223  logg[LPythia].warn("PDG ID ", pythia_id,
2224  " does not exist in ParticleType - start over.");
2225  intermediate_particles.clear();
2226  return 0;
2227  }
2228 
2229  number_of_fragments++;
2230  }
2231  }
2232  return number_of_fragments;
2233 }
2234 
2236  bool from_forward, bool separate_fragment_baryon,
2237  std::array<ThreeVector, 3> &evec_basis, double &ppos_string,
2238  double &pneg_string, double &QTrx_string_pos, double &QTrx_string_neg,
2239  double &QTry_string_pos, double &QTry_string_neg,
2240  Pythia8::FlavContainer &flav_string_pos,
2241  Pythia8::FlavContainer &flav_string_neg, std::vector<int> &pdgid_frag,
2242  std::vector<FourVector> &momentum_frag) {
2243  /* How many times we try to find flavor of qqbar pair and corresponding
2244  * hadronic species */
2245  const int n_try = 10;
2246  pdgid_frag.clear();
2247  momentum_frag.clear();
2248 
2249  if (ppos_string < 0. || pneg_string < 0.) {
2250  throw std::runtime_error("string has a negative lightcone momentum.");
2251  }
2252  double mTsqr_string = 2. * ppos_string * pneg_string;
2253  // Transverse mass of the original string
2254  double mTrn_string = std::sqrt(mTsqr_string);
2255  // Total transverse momentum of the original string
2256  double QTrx_string_tot = QTrx_string_pos + QTrx_string_neg;
2257  double QTry_string_tot = QTry_string_pos + QTry_string_neg;
2258  double QTsqr_string_tot = std::fabs(QTrx_string_tot * QTrx_string_tot) +
2259  std::fabs(QTry_string_tot * QTry_string_tot);
2260  double QTrn_string_tot = std::sqrt(QTsqr_string_tot);
2261  if (mTrn_string < QTrn_string_tot) {
2262  return 0;
2263  }
2264  // Mass of the original string
2265  double mass_string = std::sqrt(mTsqr_string - QTsqr_string_tot);
2266  logg[LPythia].debug(" Fragment off one hadron from a string ( ",
2267  flav_string_pos.id, " , ", flav_string_neg.id,
2268  " ) with mass ", mass_string, " GeV.");
2269 
2270  // Take relevant parameters from PYTHIA.
2271  const double sigma_qt_frag = pythia_hadron_->parm("StringPT:sigma");
2272  const double stop_string_mass =
2273  pythia_hadron_->parm("StringFragmentation:stopMass");
2274  const double stop_string_smear =
2275  pythia_hadron_->parm("StringFragmentation:stopSmear");
2276 
2277  // Enhance the width of transverse momentum with certain probability
2278  const double prob_enhance_qt =
2279  pythia_hadron_->parm("StringPT:enhancedFraction");
2280  double fac_enhance_qt;
2281  if (random::uniform(0., 1.) < prob_enhance_qt) {
2282  fac_enhance_qt = pythia_hadron_->parm("StringPT:enhancedWidth");
2283  } else {
2284  fac_enhance_qt = 1.;
2285  }
2286 
2287  /* Sample the transverse momentum of newly created quark-antiquark
2288  * (or diquark-antidiquark) pair.
2289  * Note that one constituent carries QT_new while -QT_new is carried by
2290  * another.
2291  * The former one is taken by the (first) fragmented hadron and
2292  * the later one will be assigned to the remaining string or
2293  * taken by the second fragmented hadron. */
2294  double QTrx_new =
2295  random::normal(0., fac_enhance_qt * sigma_qt_frag * M_SQRT1_2);
2296  double QTry_new =
2297  random::normal(0., fac_enhance_qt * sigma_qt_frag * M_SQRT1_2);
2298  logg[LPythia].debug(" Transverse momentum (", QTrx_new, ", ", QTry_new,
2299  ") GeV selected for the new qqbar pair.");
2300 
2301  /* Determine the transverse momentum of the (first) fragmented hadron.
2302  * Transverse momentum of hadron =
2303  * QT_string (of the string end) +
2304  * QT_new (of one of the quark-antiquark pair).
2305  * If the first hadron is fragmented from the forward (backward) end
2306  * of a string, then transverse momentum carried by the forward (backward)
2307  * end is taken. */
2308  double QTrx_had_1st =
2309  from_forward ? QTrx_string_pos + QTrx_new : QTrx_string_neg + QTrx_new;
2310  double QTry_had_1st =
2311  from_forward ? QTry_string_pos + QTry_new : QTry_string_neg + QTry_new;
2312  double QTrn_had_1st =
2313  std::sqrt(QTrx_had_1st * QTrx_had_1st + QTry_had_1st * QTry_had_1st);
2314 
2315  // PDG id of the (first) fragmented hadron
2316  int pdgid_had_1st = 0;
2317  // Mass of the (first) fragmented hadron
2318  double mass_had_1st = 0.;
2319  /* Constituent flavor of the original string end,
2320  * at which the (first) hadron is fragmented. */
2321  Pythia8::FlavContainer flav_old =
2322  from_forward ? flav_string_pos : flav_string_neg;
2323  /* Constituent flavor of newly created quark-antiquark pair,
2324  * which is taken by the (first) fragmented hadron.
2325  * Antiparticle of this flavor will be assigned to the remaining string,
2326  * or taken by the second fragmented hadron. */
2327  Pythia8::FlavContainer flav_new = Pythia8::FlavContainer(0);
2328  /* Sample flavor of the quark-antiquark (or diquark-antidiquark) pair
2329  * and combine with that of the original string end to find the hadronic
2330  * species. */
2331  for (int i_try = 0; i_try < n_try; i_try++) {
2332  // Sample the new flavor.
2333  flav_new = pythia_stringflav_.pick(flav_old);
2334  // Combine to get the PDG id of hadron.
2335  pdgid_had_1st = pythia_stringflav_.combine(flav_old, flav_new);
2336  if (pdgid_had_1st != 0) {
2337  // If the PDG id is found, determine mass.
2338  mass_had_1st = pythia_hadron_->particleData.mSel(pdgid_had_1st);
2339  logg[LPythia].debug(" number of tries of flavor selection : ",
2340  i_try + 1, " in StringProcess::fragment_off_hadron.");
2341  break;
2342  }
2343  }
2344  if (pdgid_had_1st == 0) {
2345  return 0;
2346  }
2347  logg[LPythia].debug(" New flavor ", flav_new.id,
2348  " selected for the string end with ", flav_old.id);
2349  logg[LPythia].debug(" PDG id ", pdgid_had_1st,
2350  " selected for the (first) fragmented hadron.");
2351  bool had_1st_baryon = pythia_hadron_->particleData.isBaryon(pdgid_had_1st);
2352  // Transverse mass of the (first) fragmented hadron
2353  double mTrn_had_1st =
2354  std::sqrt(mass_had_1st * mass_had_1st + QTrn_had_1st * QTrn_had_1st);
2355  logg[LPythia].debug(" Transverse momentum (", QTrx_had_1st, ", ",
2356  QTry_had_1st,
2357  ") GeV selected for the (first) fragmented hadron.");
2358 
2359  /* Compute the mass threshold to continue string fragmentation.
2360  * This formula is taken from StringFragmentation::energyUsedUp
2361  * in StringFragmentation.cc of PYTHIA 8. */
2362  const double mass_min_to_continue =
2363  (stop_string_mass + pythia_hadron_->particleData.m0(flav_new.id) +
2364  pythia_hadron_->particleData.m0(flav_string_pos.id) +
2365  pythia_hadron_->particleData.m0(flav_string_neg.id)) *
2366  (1. + (2. * random::uniform(0., 1.) - 1.) * stop_string_smear);
2367  /* If the string mass is lower than that threshold,
2368  * the string breaks into the last two hadrons. */
2369  bool string_into_final_two = mass_string < mass_min_to_continue;
2370  if (string_into_final_two) {
2371  logg[LPythia].debug(" The string mass is below the mass threshold ",
2372  mass_min_to_continue,
2373  " GeV : finishing with two hadrons.");
2374  }
2375 
2376  // Lightcone momentum of the (first) fragmented hadron
2377  double ppos_had_1st = 0.;
2378  double pneg_had_1st = 0.;
2379 
2380  /* Whether the string end, at which the (first) hadron is fragmented,
2381  * had a diquark or antidiquark */
2382  bool from_diquark_end =
2383  from_forward ? pythia_hadron_->particleData.isDiquark(flav_string_pos.id)
2384  : pythia_hadron_->particleData.isDiquark(flav_string_neg.id);
2385  // Whether the forward end of the string has a diquark
2386  bool has_diquark_pos =
2387  pythia_hadron_->particleData.isDiquark(flav_string_pos.id);
2388 
2389  int n_frag = 0;
2390  if (string_into_final_two) {
2391  /* In the case of a string breaking into the last two hadrons,
2392  * we determine species, mass and four-momentum of the second hadron. */
2393  // PDG id of the second fragmented hadron
2394  int pdgid_had_2nd = 0.;
2395  // Mass of the second fragmented hadron
2396  double mass_had_2nd = 0.;
2397  /* Constituent flavor of newly created quark-antiquark pair,
2398  * which is taken by the second fragmented hadron. */
2399  Pythia8::FlavContainer flav_new2 = Pythia8::FlavContainer(0);
2400  flav_new2.anti(flav_new);
2401  /* Getting a hadron from diquark and antidiquark does not always work.
2402  * So, if this is the case, start over. */
2403  if (pythia_hadron_->particleData.isDiquark(flav_string_neg.id) &&
2404  pythia_hadron_->particleData.isDiquark(flav_new2.id) && from_forward) {
2405  return 0;
2406  }
2407  if (pythia_hadron_->particleData.isDiquark(flav_string_pos.id) &&
2408  pythia_hadron_->particleData.isDiquark(flav_new2.id) && !from_forward) {
2409  return 0;
2410  }
2411  for (int i_try = 0; i_try < n_try; i_try++) {
2412  // Combine to get the PDG id of the second hadron.
2413  pdgid_had_2nd =
2414  from_forward ? pythia_stringflav_.combine(flav_string_neg, flav_new2)
2415  : pythia_stringflav_.combine(flav_string_pos, flav_new2);
2416  if (pdgid_had_2nd != 0) {
2417  // If the PDG id is found, determine mass.
2418  mass_had_2nd = pythia_hadron_->particleData.mSel(pdgid_had_2nd);
2419  break;
2420  }
2421  }
2422  if (pdgid_had_2nd == 0) {
2423  return 0;
2424  }
2425  logg[LPythia].debug(" PDG id ", pdgid_had_2nd,
2426  " selected for the (second) fragmented hadron.");
2427  bool had_2nd_baryon = pythia_hadron_->particleData.isBaryon(pdgid_had_2nd);
2428 
2429  /* Determine transverse momentum carried by the second hadron.
2430  * If the first hadron fragmented from the forward (backward) end
2431  * of a string, transvere momentum at the backward (forward) end will
2432  * contribute.
2433  * Transverse momentum of newly created constituent
2434  * must be added as well. */
2435  double QTrx_had_2nd =
2436  from_forward ? QTrx_string_neg - QTrx_new : QTrx_string_pos - QTrx_new;
2437  double QTry_had_2nd =
2438  from_forward ? QTry_string_neg - QTry_new : QTry_string_pos - QTry_new;
2439  double QTrn_had_2nd =
2440  std::sqrt(QTrx_had_2nd * QTrx_had_2nd + QTry_had_2nd * QTry_had_2nd);
2441  double mTrn_had_2nd =
2442  std::sqrt(mass_had_2nd * mass_had_2nd + QTrn_had_2nd * QTrn_had_2nd);
2443  logg[LPythia].debug(" Transverse momentum (", QTrx_had_2nd, ", ",
2444  QTry_had_2nd,
2445  ") GeV selected for the (second) fragmented hadron.");
2446 
2447  double ppos_had_2nd = 0.;
2448  double pneg_had_2nd = 0.;
2449 
2450  /* Compute lightcone momenta of the final two hadrons.
2451  * If the fragmentation begins at the forward (backward) end of a string,
2452  * the first (second) hadron is the forward one and the second (first)
2453  * hadron is the backward one. */
2454  bool found_kinematics =
2455  from_forward
2457  separate_fragment_baryon && has_diquark_pos && had_1st_baryon,
2458  ppos_string, pneg_string, mTrn_had_1st, mTrn_had_2nd,
2459  ppos_had_1st, ppos_had_2nd, pneg_had_1st, pneg_had_2nd)
2461  separate_fragment_baryon && has_diquark_pos && had_2nd_baryon,
2462  ppos_string, pneg_string, mTrn_had_2nd, mTrn_had_1st,
2463  ppos_had_2nd, ppos_had_1st, pneg_had_2nd, pneg_had_1st);
2464  if (!found_kinematics) {
2465  return 0;
2466  }
2467 
2468  // The entire string breaks into hadrons, so there is no momentum left.
2469  ppos_string = 0.;
2470  pneg_string = 0.;
2471  QTrx_string_pos = 0.;
2472  QTry_string_pos = 0.;
2473 
2474  // Add the first hadron to the list.
2475  pdgid_frag.push_back(pdgid_had_1st);
2476  FourVector mom_had_1st = FourVector(
2477  (ppos_had_1st + pneg_had_1st) * M_SQRT1_2,
2478  evec_basis[0] * (ppos_had_1st - pneg_had_1st) * M_SQRT1_2 +
2479  evec_basis[1] * QTrx_had_1st + evec_basis[2] * QTry_had_1st);
2480  momentum_frag.push_back(mom_had_1st);
2481 
2482  // Add the second hadron to the list.
2483  pdgid_frag.push_back(pdgid_had_2nd);
2484  FourVector mom_had_2nd = FourVector(
2485  (ppos_had_2nd + pneg_had_2nd) * M_SQRT1_2,
2486  evec_basis[0] * (ppos_had_2nd - pneg_had_2nd) * M_SQRT1_2 +
2487  evec_basis[1] * QTrx_had_2nd + evec_basis[2] * QTry_had_2nd);
2488  momentum_frag.push_back(mom_had_2nd);
2489 
2490  n_frag += 2;
2491  } else {
2492  /* If the string mass is large enough (larger than the threshold),
2493  * perform the normal fragmentation.
2494  * Different sets of parameters for the LUND fragmentation function
2495  * are used, depending on whether the (first) fragmented hadrons is
2496  * the leading baryon. */
2497  double stringz_a_use, stringz_b_use;
2498  /* If the firstly fragmented hadron from the diquark end is a baryon,
2499  * it can be considered to be the leading baryon. */
2500  if (separate_fragment_baryon && from_diquark_end && had_1st_baryon) {
2501  stringz_a_use = stringz_a_leading_;
2502  stringz_b_use = stringz_b_leading_;
2503  } else {
2504  stringz_a_use = stringz_a_produce_;
2505  stringz_b_use = stringz_b_produce_;
2506  }
2507 
2508  /* Sample the lightcone momentum fraction from
2509  * the LUND fragmentation function. */
2510  double xfrac = sample_zLund(stringz_a_use, stringz_b_use, mTrn_had_1st);
2511  if (from_forward) {
2512  /* If the (first) hadron is fragmented from the forward end,
2513  * it is the lightcone momentum fraction of p^+ */
2514  ppos_had_1st = xfrac * ppos_string;
2515  pneg_had_1st = 0.5 * mTrn_had_1st * mTrn_had_1st / ppos_had_1st;
2516  if (pneg_had_1st > pneg_string) {
2517  return 0;
2518  }
2519  } else {
2520  /* If the (first) hadron is fragmented from the backward end,
2521  * it is the lightcone momentum fraction of p^- */
2522  pneg_had_1st = xfrac * pneg_string;
2523  ppos_had_1st = 0.5 * mTrn_had_1st * mTrn_had_1st / pneg_had_1st;
2524  if (ppos_had_1st > ppos_string) {
2525  return 0;
2526  }
2527  }
2528 
2529  // Add PDG id and four-momentum of the (first) hadron to the list.
2530  pdgid_frag.push_back(pdgid_had_1st);
2531  FourVector mom_had_1st = FourVector(
2532  (ppos_had_1st + pneg_had_1st) * M_SQRT1_2,
2533  evec_basis[0] * (ppos_had_1st - pneg_had_1st) * M_SQRT1_2 +
2534  evec_basis[1] * QTrx_had_1st + evec_basis[2] * QTry_had_1st);
2535  momentum_frag.push_back(mom_had_1st);
2536 
2537  // Update lightcone momentum of the string.
2538  ppos_string -= ppos_had_1st;
2539  pneg_string -= pneg_had_1st;
2540  /* Update flavor and transverse momentum of the string end,
2541  * from which the (first) hadron is fragmented.
2542  * Flavor of the new string end is antiparticle of
2543  * the constituent taken by the hadron.
2544  * Transverse momentum of the new string end is opposite to that
2545  * of the constituent taken by the hadron. */
2546  if (from_forward) {
2547  /* Update the forward end of the string
2548  * if hadron is fragmented from there. */
2549  flav_string_pos.anti(flav_new);
2550  QTrx_string_pos = -QTrx_new;
2551  QTry_string_pos = -QTry_new;
2552  } else {
2553  /* Update the backward end of the string
2554  * if hadron is fragmented from there. */
2555  flav_string_neg.anti(flav_new);
2556  QTrx_string_neg = -QTrx_new;
2557  QTry_string_neg = -QTry_new;
2558  }
2559 
2560  n_frag += 1;
2561  }
2562 
2563  return n_frag;
2564 }
2565 
2567  const int baryon_number =
2568  pythia_hadron_->particleData.baryonNumberType(idq1) +
2569  pythia_hadron_->particleData.baryonNumberType(idq2);
2570 
2571  int pdgid_hadron = 0;
2572  /* PDG id of the leading baryon from valence quark constituent.
2573  * First, try with the PYTHIA machinary. */
2574  Pythia8::FlavContainer flav1 = Pythia8::FlavContainer(idq1);
2575  Pythia8::FlavContainer flav2 = Pythia8::FlavContainer(idq2);
2576  const int n_try = 10;
2577  for (int i_try = 0; i_try < n_try; i_try++) {
2578  pdgid_hadron = pythia_stringflav_.combine(flav1, flav2);
2579  if (pdgid_hadron != 0) {
2580  return pdgid_hadron;
2581  }
2582  }
2583 
2584  /* If PYTHIA machinary does not work, determine type of the leading baryon
2585  * based on the quantum numbers and mass. */
2586 
2587  // net quark number of d, u, s, c and b flavors
2588  std::array<int, 5> frag_net_q;
2589  /* Evaluate total net quark number of baryon (antibaryon)
2590  * from the valence quark constituents. */
2591  for (int iq = 0; iq < 5; iq++) {
2592  int nq1 =
2593  pythia_hadron_->particleData.nQuarksInCode(std::abs(idq1), iq + 1);
2594  int nq2 =
2595  pythia_hadron_->particleData.nQuarksInCode(std::abs(idq2), iq + 1);
2596  nq1 = idq1 > 0 ? nq1 : -nq1;
2597  nq2 = idq2 > 0 ? nq2 : -nq2;
2598  frag_net_q[iq] = nq1 + nq2;
2599  }
2600  const int frag_iso3 = frag_net_q[1] - frag_net_q[0];
2601  const int frag_strange = -frag_net_q[2];
2602  const int frag_charm = frag_net_q[3];
2603  const int frag_bottom = -frag_net_q[4];
2604  logg[LPythia].debug(" conserved charges : iso3 = ", frag_iso3,
2605  ", strangeness = ", frag_strange,
2606  ", charmness = ", frag_charm,
2607  ", bottomness = ", frag_bottom);
2608 
2609  std::vector<int> pdgid_possible;
2610  std::vector<double> weight_possible;
2611  std::vector<double> weight_summed;
2612  /* loop over hadronic species
2613  * Any hadron with the same valence quark contents is allowed and
2614  * the probability goes like spin degeneracy over mass. */
2615  for (auto &ptype : ParticleType::list_all()) {
2616  if (!ptype.is_hadron()) {
2617  continue;
2618  }
2619  const int pdgid = ptype.pdgcode().get_decimal();
2620  if ((pythia_hadron_->particleData.isParticle(pdgid)) &&
2621  (baryon_number == 3 * ptype.pdgcode().baryon_number()) &&
2622  (frag_iso3 == ptype.pdgcode().isospin3()) &&
2623  (frag_strange == ptype.pdgcode().strangeness()) &&
2624  (frag_charm == ptype.pdgcode().charmness()) &&
2625  (frag_bottom == ptype.pdgcode().bottomness())) {
2626  const int spin_degeneracy = ptype.pdgcode().spin_degeneracy();
2627  const double mass_pole = ptype.mass();
2628  const double weight = static_cast<double>(spin_degeneracy) / mass_pole;
2629  pdgid_possible.push_back(pdgid);
2630  weight_possible.push_back(weight);
2631 
2632  logg[LPythia].debug(" PDG id ", pdgid, " is possible with weight ",
2633  weight);
2634  }
2635  }
2636  const int n_possible = pdgid_possible.size();
2637  weight_summed.push_back(0.);
2638  for (int i = 0; i < n_possible; i++) {
2639  weight_summed.push_back(weight_summed[i] + weight_possible[i]);
2640  }
2641 
2642  /* Sample baryon (antibaryon) specie,
2643  * which is fragmented from the leading diquark (anti-diquark). */
2644  const double uspc = random::uniform(0., weight_summed[n_possible]);
2645  for (int i = 0; i < n_possible; i++) {
2646  if ((uspc >= weight_summed[i]) && (uspc < weight_summed[i + 1])) {
2647  return pdgid_possible[i];
2648  }
2649  }
2650 
2651  return 0;
2652 }
2653 
2654 int StringProcess::get_resonance_from_quark(int idq1, int idq2, double mass) {
2655  // if the mass is too low, return 0 (failure).
2656  if (mass < pion_mass) {
2657  return 0;
2658  }
2659 
2660  /* It checks whether one has a valid input
2661  * the string ends. */
2662 
2663  // idq1 is supposed to be a quark or anti-diquark.
2664  bool end1_is_quark = idq1 > 0 && pythia_hadron_->particleData.isQuark(idq1);
2665  bool end1_is_antidiq =
2666  idq1 < 0 && pythia_hadron_->particleData.isDiquark(idq1);
2667  // idq2 is supposed to be a anti-quark or diquark.
2668  bool end2_is_antiq = idq2 < 0 && pythia_hadron_->particleData.isQuark(idq2);
2669  bool end2_is_diquark =
2670  idq2 > 0 && pythia_hadron_->particleData.isDiquark(idq2);
2671 
2672  int baryon;
2673  if (end1_is_quark) {
2674  if (end2_is_antiq) {
2675  // we have a mesonic resonance from a quark-antiquark pair.
2676  baryon = 0;
2677  } else if (end2_is_diquark) {
2678  // we have a baryonic resonance from a quark-diquark pair.
2679  baryon = 1;
2680  } else {
2681  return 0;
2682  }
2683  } else if (end1_is_antidiq) {
2684  if (end2_is_antiq) {
2685  // we have a antibaryonic resonance from a antiquark-antidiquark pair.
2686  baryon = -1;
2687  } else {
2688  return 0;
2689  }
2690  } else {
2691  return 0;
2692  }
2693 
2694  /* array for the net quark numbers of the constituents.
2695  * net_qnumber[0, 1, 2, 3 and 4] correspond respectively to
2696  * d, u, s, c, b quark flavors. */
2697  std::array<int, 5> net_qnumber;
2698  for (int iflav = 0; iflav < 5; iflav++) {
2699  net_qnumber[iflav] = 0;
2700 
2701  int qnumber1 =
2702  pythia_hadron_->particleData.nQuarksInCode(std::abs(idq1), iflav + 1);
2703  if (idq1 < 0) {
2704  // anti-diquark gets an extra minus sign.
2705  qnumber1 = -qnumber1;
2706  }
2707  net_qnumber[iflav] += qnumber1;
2708 
2709  int qnumber2 =
2710  pythia_hadron_->particleData.nQuarksInCode(std::abs(idq2), iflav + 1);
2711  if (idq2 < 0) {
2712  // anti-quark gets an extra minus sign.
2713  qnumber2 = -qnumber2;
2714  }
2715  net_qnumber[iflav] += qnumber2;
2716  }
2717 
2718  // List of PDG ids of resonances with the same quantum number.
2719  std::vector<int> pdgid_possible;
2720  // Corresponding mass differences.
2721  std::vector<double> mass_diff;
2722  for (auto &ptype : ParticleType::list_all()) {
2723  if (!ptype.is_hadron() || ptype.is_stable() ||
2724  ptype.pdgcode().baryon_number() != baryon) {
2725  // Only resonances with the same baryon number are considered.
2726  continue;
2727  }
2728  const int pdgid = ptype.pdgcode().get_decimal();
2729  const double mass_min = ptype.min_mass_spectral();
2730  if (mass < mass_min) {
2731  // A resoance with mass lower than its minimum threshold is not allowed.
2732  continue;
2733  }
2734 
2735  if (ptype.pdgcode().isospin3() != net_qnumber[1] - net_qnumber[0]) {
2736  // check isospin3.
2737  continue;
2738  }
2739  if (ptype.pdgcode().strangeness() != -net_qnumber[2]) {
2740  // check strangeness.
2741  continue;
2742  }
2743  if (ptype.pdgcode().charmness() != net_qnumber[3]) {
2744  // check charmness.
2745  continue;
2746  }
2747  if (ptype.pdgcode().bottomness() != -net_qnumber[4]) {
2748  // check bottomness.
2749  continue;
2750  }
2751 
2752  const double mass_pole = ptype.mass();
2753  // Add the PDG id and mass difference to the vector array.
2754  pdgid_possible.push_back(pdgid);
2755  mass_diff.push_back(mass - mass_pole);
2756  }
2757 
2758  const int n_res = pdgid_possible.size();
2759  if (n_res == 0) {
2760  // If there is no possible resonance found, return 0 (failure).
2761  return 0;
2762  }
2763 
2764  int ires_closest = 0;
2765  double mass_diff_min = std::fabs(mass_diff[0]);
2766  /* Find a resonance whose pole mass is closest to
2767  * the input mass. */
2768  for (int ires = 1; ires < n_res; ires++) {
2769  if (std::fabs(mass_diff[ires]) < mass_diff_min) {
2770  ires_closest = ires;
2771  mass_diff_min = mass_diff[ires];
2772  }
2773  }
2774  logg[LPythia].debug("Quark constituents ", idq1, " and ", idq2, " with mass ",
2775  mass, " (GeV) turned into a resonance ",
2776  pdgid_possible[ires_closest]);
2777  return pdgid_possible[ires_closest];
2778 }
2779 
2781  bool separate_fragment_hadron, double ppos_string, double pneg_string,
2782  double mTrn_had_forward, double mTrn_had_backward, double &ppos_had_forward,
2783  double &ppos_had_backward, double &pneg_had_forward,
2784  double &pneg_had_backward) {
2785  const double mTsqr_string = 2. * ppos_string * pneg_string;
2786  if (mTsqr_string < 0.) {
2787  return false;
2788  }
2789  const double mTrn_string = std::sqrt(mTsqr_string);
2790  if (mTrn_string < mTrn_had_forward + mTrn_had_backward) {
2791  return false;
2792  }
2793 
2794  // square of transvere mass of the forward hadron
2795  const double mTsqr_had_forward = mTrn_had_forward * mTrn_had_forward;
2796  // square of transvere mass of the backward hadron
2797  const double mTsqr_had_backward = mTrn_had_backward * mTrn_had_backward;
2798 
2799  /* The following part determines lightcone momentum fraction of p^+
2800  * carried by each hadron.
2801  * Lightcone momenta of the forward and backward hadrons are
2802  * p^+ forward = (xe_pos + xpz_pos) * p^+ string,
2803  * p^- forward = (xe_pos - xpz_pos) * p^- string,
2804  * p^+ backward = (xe_neg - xpz_pos) * p^+ string and
2805  * p^- backward = (xe_neg + xpz_pos) * p^- string.
2806  * where xe_pos and xe_neg satisfy xe_pos + xe_neg = 1.
2807  * Then evaluate xe_pos, xe_neg and xpz_pos in terms of
2808  * the transverse masses of hadrons and string. */
2809 
2810  // Express xe_pos and xe_neg in terms of the transverse masses.
2811  const double xm_diff =
2812  (mTsqr_had_forward - mTsqr_had_backward) / mTsqr_string;
2813  const double xe_pos = 0.5 * (1. + xm_diff);
2814  const double xe_neg = 0.5 * (1. - xm_diff);
2815 
2816  // Express xpz_pos in terms of the transverse masses.
2817  const double lambda_sqr =
2818  pow_int(mTsqr_string - mTsqr_had_forward - mTsqr_had_backward, 2) -
2819  4. * mTsqr_had_forward * mTsqr_had_backward;
2820  if (lambda_sqr <= 0.) {
2821  return false;
2822  }
2823  const double lambda = std::sqrt(lambda_sqr);
2824  const double b_lund =
2825  separate_fragment_hadron ? stringz_b_leading_ : stringz_b_produce_;
2826  /* The probability to flip sign of xpz_pos is taken from
2827  * StringFragmentation::finalTwo in StringFragmentation.cc
2828  * of PYTHIA 8. */
2829  const double prob_reverse =
2830  std::exp(-b_lund * lambda) / (1. + std::exp(-b_lund * lambda));
2831  double xpz_pos = 0.5 * lambda / mTsqr_string;
2832  if (random::uniform(0., 1.) < prob_reverse) {
2833  xpz_pos = -xpz_pos;
2834  }
2835 
2836  ppos_had_forward = (xe_pos + xpz_pos) * ppos_string;
2837  ppos_had_backward = (xe_neg - xpz_pos) * ppos_string;
2838 
2839  pneg_had_forward = 0.5 * mTsqr_had_forward / ppos_had_forward;
2840  pneg_had_backward = 0.5 * mTsqr_had_backward / ppos_had_backward;
2841 
2842  return true;
2843 }
2844 
2845 double StringProcess::sample_zLund(double a, double b, double mTrn) {
2846  // the lightcone momentum fraction x
2847  double xfrac = 0.;
2848  bool xfrac_accepted = false;
2849  /* First sample the inverse 1/x of the lightcone momentum fraction.
2850  * Then, obtain x itself.
2851  * The probability distribution function for the inverse of x is
2852  * PDF(u = 1/x) = (1/u) * (1 - 1/u)^a * exp(-b * mTrn^2 * u)
2853  * with 1 < u < infinity.
2854  * The rejection method can be used with an envelop function
2855  * ENV(u) = exp(-b * mTrn^2 * u). */
2856  while (!xfrac_accepted) {
2857  const double fac_env = b * mTrn * mTrn;
2858  const double u_aux = random::uniform(0., 1.);
2859  /* Sample u = 1/x according to the envelop function
2860  * ENV(u) = exp(-b * mTrn^2 * u). */
2861  const double xfrac_inv = 1. - std::log(u_aux) / fac_env;
2862  assert(xfrac_inv >= 1.);
2863  /* Evaluate the ratio of the real probability distribution function to
2864  * the envelop function. */
2865  const double xf_ratio = std::pow(1. - 1. / xfrac_inv, a) / xfrac_inv;
2866  // Determine whether the sampled value will be accepted.
2867  if (random::uniform(0., 1.) <= xf_ratio) {
2868  /* If the sampled value of 1/x is accepted,
2869  * obtain the value of x. */
2870  xfrac = 1. / xfrac_inv;
2871  xfrac_accepted = true;
2872  }
2873  }
2874  return xfrac;
2875 }
2876 
2878  Pythia8::Event &event_fragments, std::array<ThreeVector, 3> &evec_basis,
2879  double ppos_string, double pneg_string, double QTrx_string,
2880  double QTry_string, double QTrx_add_pos, double QTry_add_pos,
2881  double QTrx_add_neg, double QTry_add_neg) {
2882  logg[LPythia].debug("Correcting the kinematics of fragmented hadrons...");
2883 
2884  if (ppos_string < 0. || pneg_string < 0.) {
2885  logg[LPythia].debug(
2886  " wrong lightcone momenta of string : ppos_string (GeV) = ",
2887  ppos_string, " pneg_string (GeV) = ", pneg_string);
2888  return false;
2889  }
2890  // Momentum rapidity of the final string
2891  const double yrapid_string = 0.5 * std::log(ppos_string / pneg_string);
2892  logg[LOutput].debug("Momentum-space rapidity of the string should be ",
2893  yrapid_string);
2894 
2895  // Transverse mass of the final string
2896  const double mTrn_string = std::sqrt(2. * ppos_string * pneg_string);
2897  logg[LOutput].debug("Transvere mass (GeV) of the string should be ",
2898  mTrn_string);
2899  // Transverse momentum of the final string
2900  const double QTrn_string =
2901  std::sqrt(QTrx_string * QTrx_string + QTry_string * QTry_string);
2902  if (mTrn_string < QTrn_string) {
2903  logg[LOutput].debug(
2904  " wrong transverse mass of string : mTrn_string (GeV) = ", mTrn_string,
2905  " QTrn_string (GeV) = ", QTrn_string);
2906  return false;
2907  }
2908  const double msqr_string =
2909  mTrn_string * mTrn_string - QTrn_string * QTrn_string;
2910  // Mass of the final string
2911  const double mass_string = std::sqrt(msqr_string);
2912  logg[LOutput].debug("The string mass (GeV) should be ", mass_string);
2913 
2914  /* If there is no transverse momentum to be added to the string ends,
2915  * skip the entire procedure and return. */
2916  if (std::fabs(QTrx_add_pos) < small_number * mass_string &&
2917  std::fabs(QTry_add_pos) < small_number * mass_string &&
2918  std::fabs(QTrx_add_neg) < small_number * mass_string &&
2919  std::fabs(QTry_add_neg) < small_number * mass_string) {
2920  logg[LOutput].debug(" no need to add transverse momenta - skipping.");
2921  return true;
2922  }
2923 
2924  FourVector ptot_string_ini = FourVector(0., 0., 0., 0.);
2925  // Compute total four-momentum of the initial string.
2926  for (int ipyth = 1; ipyth < event_fragments.size(); ipyth++) {
2927  if (!event_fragments[ipyth].isFinal()) {
2928  continue;
2929  }
2930 
2931  FourVector p_frag =
2932  FourVector(event_fragments[ipyth].e(), event_fragments[ipyth].px(),
2933  event_fragments[ipyth].py(), event_fragments[ipyth].pz());
2934  ptot_string_ini += p_frag;
2935  }
2936  const double E_string_ini = ptot_string_ini.x0();
2937  const double pz_string_ini = ptot_string_ini.threevec() * evec_basis[0];
2938  const double ppos_string_ini = (E_string_ini + pz_string_ini) * M_SQRT1_2;
2939  const double pneg_string_ini = (E_string_ini - pz_string_ini) * M_SQRT1_2;
2940  // Compute the momentum rapidity of the initial string.
2941  const double yrapid_string_ini =
2942  0.5 * std::log(ppos_string_ini / pneg_string_ini);
2943  /* Then, boost into the frame in which string is at rest in the
2944  * longitudinal direction. */
2945  shift_rapidity_event(event_fragments, evec_basis, 1., -yrapid_string_ini);
2946 
2947  int ip_forward = 0;
2948  int ip_backward = 0;
2949  double y_forward = 0.;
2950  double y_backward = 0.;
2951  ptot_string_ini = FourVector(0., 0., 0., 0.);
2952  // Find the most forward and backward hadrons based on the momentum rapidity.
2953  for (int ipyth = 1; ipyth < event_fragments.size(); ipyth++) {
2954  if (!event_fragments[ipyth].isFinal()) {
2955  continue;
2956  }
2957 
2958  FourVector p_frag =
2959  FourVector(event_fragments[ipyth].e(), event_fragments[ipyth].px(),
2960  event_fragments[ipyth].py(), event_fragments[ipyth].pz());
2961  ptot_string_ini += p_frag;
2962 
2963  const double E_frag = p_frag.x0();
2964  const double pl_frag = p_frag.threevec() * evec_basis[0];
2965  double y_current = 0.5 * std::log((E_frag + pl_frag) / (E_frag - pl_frag));
2966  if (y_current > y_forward) {
2967  ip_forward = ipyth;
2968  y_forward = y_current;
2969  }
2970  if (y_current < y_backward) {
2971  ip_backward = ipyth;
2972  y_backward = y_current;
2973  }
2974  }
2975  logg[LOutput].debug(" The most forward hadron is ip_forward = ", ip_forward,
2976  " with rapidity ", y_forward);
2977  logg[LOutput].debug(" The most backward hadron is ip_backward = ",
2978  ip_backward, " with rapidity ", y_backward);
2979 
2980  const double px_string_ini = ptot_string_ini.threevec() * evec_basis[1];
2981  const double py_string_ini = ptot_string_ini.threevec() * evec_basis[2];
2982 
2983  /* Check if the transverse momentum px is conserved i.e.,
2984  * px of the initial string + px to be added = px of the final string */
2985  bool correct_px = std::fabs(px_string_ini + QTrx_add_pos + QTrx_add_neg -
2986  QTrx_string) < small_number * mass_string;
2987  if (!correct_px) {
2988  logg[LOutput].debug(
2989  " input transverse momenta in x-axis are not consistent.");
2990  return false;
2991  }
2992  /* Check if the transverse momentum py is conserved i.e.,
2993  * py of the initial string + py to be added = py of the final string */
2994  bool correct_py = std::fabs(py_string_ini + QTry_add_pos + QTry_add_neg -
2995  QTry_string) < small_number * mass_string;
2996  if (!correct_py) {
2997  logg[LOutput].debug(
2998  " input transverse momenta in y-axis are not consistent.");
2999  return false;
3000  }
3001 
3002  Pythia8::Vec4 pvec_string_now =
3003  set_Vec4(ptot_string_ini.x0(), ptot_string_ini.threevec());
3004 
3005  logg[LOutput].debug(
3006  " Adding transverse momentum to the most forward hadron.");
3007  pvec_string_now -= event_fragments[ip_forward].p();
3008  const double mass_frag_pos = event_fragments[ip_forward].p().mCalc();
3009  // Four-momentum of the most forward hadron
3010  FourVector p_old_frag_pos = FourVector(
3011  event_fragments[ip_forward].e(), event_fragments[ip_forward].px(),
3012  event_fragments[ip_forward].py(), event_fragments[ip_forward].pz());
3013  // Add transverse momentum to it.
3014  ThreeVector mom_new_frag_pos = p_old_frag_pos.threevec() +
3015  QTrx_add_pos * evec_basis[1] +
3016  QTry_add_pos * evec_basis[2];
3017  // Re-calculate the energy.
3018  double E_new_frag_pos =
3019  std::sqrt(mom_new_frag_pos.sqr() + mass_frag_pos * mass_frag_pos);
3020  Pythia8::Vec4 pvec_new_frag_pos = set_Vec4(E_new_frag_pos, mom_new_frag_pos);
3021  pvec_string_now += pvec_new_frag_pos;
3022  // Update the event record.
3023  event_fragments[ip_forward].p(pvec_new_frag_pos);
3024 
3025  logg[LOutput].debug(
3026  " Adding transverse momentum to the most backward hadron.");
3027  pvec_string_now -= event_fragments[ip_backward].p();
3028  const double mass_frag_neg = event_fragments[ip_backward].p().mCalc();
3029  // Four-momentum of the most backward hadron
3030  FourVector p_old_frag_neg = FourVector(
3031  event_fragments[ip_backward].e(), event_fragments[ip_backward].px(),
3032  event_fragments[ip_backward].py(), event_fragments[ip_backward].pz());
3033  // Add transverse momentum to it.
3034  ThreeVector mom_new_frag_neg = p_old_frag_neg.threevec() +
3035  QTrx_add_neg * evec_basis[1] +
3036  QTry_add_neg * evec_basis[2];
3037  // Re-calculate the energy.
3038  double E_new_frag_neg =
3039  std::sqrt(mom_new_frag_neg.sqr() + mass_frag_neg * mass_frag_neg);
3040  Pythia8::Vec4 pvec_new_frag_neg = set_Vec4(E_new_frag_neg, mom_new_frag_neg);
3041  pvec_string_now += pvec_new_frag_neg;
3042  // Update the event record.
3043  event_fragments[ip_backward].p(pvec_new_frag_neg);
3044 
3045  // Update the event record with total four-momentum of the current string.
3046  event_fragments[0].p(pvec_string_now);
3047  event_fragments[0].m(pvec_string_now.mCalc());
3048 
3049  int n_frag = 0;
3050  // Sum of transverse masses of all fragmented hadrons.
3051  double mTrn_frag_all = 0.;
3052  for (int ipyth = 1; ipyth < event_fragments.size(); ipyth++) {
3053  if (!event_fragments[ipyth].isFinal()) {
3054  continue;
3055  }
3056 
3057  n_frag += 1;
3058  FourVector p_frag =
3059  FourVector(event_fragments[ipyth].e(), event_fragments[ipyth].px(),
3060  event_fragments[ipyth].py(), event_fragments[ipyth].pz());
3061  ptot_string_ini += p_frag;
3062 
3063  const double E_frag = p_frag.x0();
3064  const double pl_frag = p_frag.threevec() * evec_basis[0];
3065  const double ppos_frag = (E_frag + pl_frag) * M_SQRT1_2;
3066  const double pneg_frag = (E_frag - pl_frag) * M_SQRT1_2;
3067  const double mTrn_frag = std::sqrt(2. * ppos_frag * pneg_frag);
3068  mTrn_frag_all += mTrn_frag;
3069  }
3070  logg[LOutput].debug(
3071  "Sum of transverse masses (GeV) of all fragmented hadrons : ",
3072  mTrn_frag_all);
3073  /* If the transverse mass of the (final) string is smaller than
3074  * the sum of transverse masses, kinematics cannot be determined. */
3075  if (mTrn_string < mTrn_frag_all) {
3076  logg[LOutput].debug(" which is larger than mT of the actual string ",
3077  mTrn_string);
3078  return false;
3079  }
3080 
3081  double mass_string_now = pvec_string_now.mCalc();
3082  double msqr_string_now = mass_string_now * mass_string_now;
3083  // Total four-momentum of the current string
3084  FourVector p_string_now =
3085  FourVector(pvec_string_now.e(), pvec_string_now.px(),
3086  pvec_string_now.py(), pvec_string_now.pz());
3087  double E_string_now = p_string_now.x0();
3088  double pz_string_now = p_string_now.threevec() * evec_basis[0];
3089  logg[LOutput].debug("The string mass (GeV) at this point : ",
3090  mass_string_now);
3091  double ppos_string_now = (E_string_now + pz_string_now) * M_SQRT1_2;
3092  double pneg_string_now = (E_string_now - pz_string_now) * M_SQRT1_2;
3093  // Momentum rapidity of the current string
3094  double yrapid_string_now = 0.5 * std::log(ppos_string_now / pneg_string_now);
3095  logg[LOutput].debug("The momentum-space rapidity of string at this point : ",
3096  yrapid_string_now);
3097  logg[LOutput].debug(
3098  "The momentum-space rapidities of hadrons will be changed.");
3099  const int niter_max = 10000;
3100  bool accepted = false;
3101  double fac_all_yrapid = 1.;
3102  /* Rescale momentum rapidities of hadrons by replacing
3103  * y_hadron with y_string_now + fac_yrapid * (y_hadron - y_string_now).
3104  * This is done iteratively by finding the value of fac_yrapid which gives
3105  * the correct string mass. */
3106  for (int iiter = 0; iiter < niter_max; iiter++) {
3107  if (std::fabs(mass_string_now - mass_string) < really_small * mass_string) {
3108  accepted = true;
3109  break;
3110  }
3111  double E_deriv = 0.;
3112  double pz_deriv = 0.;
3113 
3114  /* Have a Taylor series of mass square as a linear function
3115  * of fac_yrapid and find a trial value of fac_yrapid. */
3116  for (int ipyth = 1; ipyth < event_fragments.size(); ipyth++) {
3117  if (!event_fragments[ipyth].isFinal()) {
3118  continue;
3119  }
3120 
3121  FourVector p_frag =
3122  FourVector(event_fragments[ipyth].e(), event_fragments[ipyth].px(),
3123  event_fragments[ipyth].py(), event_fragments[ipyth].pz());
3124  const double E_frag = p_frag.x0();
3125  const double pl_frag = p_frag.threevec() * evec_basis[0];
3126  const double ppos_frag = (E_frag + pl_frag) * M_SQRT1_2;
3127  const double pneg_frag = (E_frag - pl_frag) * M_SQRT1_2;
3128  const double mTrn_frag = std::sqrt(2. * ppos_frag * pneg_frag);
3129  const double y_frag = 0.5 * std::log(ppos_frag / pneg_frag);
3130 
3131  E_deriv += mTrn_frag * (y_frag - yrapid_string_now) * std::sinh(y_frag);
3132  pz_deriv += mTrn_frag * (y_frag - yrapid_string_now) * std::cosh(y_frag);
3133  }
3134  double slope = 2. * (E_string_now * E_deriv - pz_string_now * pz_deriv);
3135  double fac_yrapid = 1. + std::tanh((msqr_string - msqr_string_now) / slope);
3136  fac_all_yrapid *= fac_yrapid;
3137 
3138  // Replace momentum rapidities of hadrons.
3139  shift_rapidity_event(event_fragments, evec_basis, fac_yrapid,
3140  (1. - fac_yrapid) * yrapid_string_now);
3141  // Update the four-momentum and mass of the current string
3142  pvec_string_now = event_fragments[0].p();
3143  mass_string_now = pvec_string_now.mCalc();
3144  msqr_string_now = mass_string_now * mass_string_now;
3145  p_string_now = FourVector(pvec_string_now.e(), pvec_string_now.px(),
3146  pvec_string_now.py(), pvec_string_now.pz());
3147  E_string_now = p_string_now.x0();
3148  pz_string_now = p_string_now.threevec() * evec_basis[0];
3149  ppos_string_now = (E_string_now + pz_string_now) * M_SQRT1_2;
3150  pneg_string_now = (E_string_now - pz_string_now) * M_SQRT1_2;
3151  yrapid_string_now = 0.5 * std::log(ppos_string_now / pneg_string_now);
3152  logg[LOutput].debug(" step ", iiter + 1, " : fac_yrapid = ", fac_yrapid,
3153  " , string mass (GeV) = ", mass_string_now,
3154  " , string rapidity = ", yrapid_string_now);
3155  }
3156 
3157  if (!accepted) {
3158  logg[LOutput].debug(" Too many iterations in rapidity rescaling.");
3159  return false;
3160  }
3161  logg[LOutput].debug(
3162  "The overall factor multiplied to the rapidities of hadrons = ",
3163  fac_all_yrapid);
3164  logg[LOutput].debug("The momentum-space rapidity of string at this point : ",
3165  yrapid_string_now);
3166  const double y_diff = yrapid_string - yrapid_string_now;
3167  logg[LOutput].debug("The hadrons will be boosted by rapidity ", y_diff,
3168  " for the longitudinal momentum conservation.");
3169 
3170  // Boost the hadrons back into the original frame.
3171  shift_rapidity_event(event_fragments, evec_basis, 1., y_diff);
3172 
3173  return true;
3174 }
3175 
3177  double suppression_factor) {
3178  int nbaryon = data.pdgcode().baryon_number();
3179  if (nbaryon == 0) {
3180  // Mesons always get a scaling factor of 1/2 since there is never
3181  // a q-qbar pair at the end of a string so nquark is always 1
3182  data.set_cross_section_scaling_factor(0.5 * suppression_factor);
3183  } else if (data.is_baryon()) {
3184  // Leading baryons get a factor of 2/3 if they carry 2
3185  // and 1/3 if they carry 1 of the strings valence quarks
3186  data.set_cross_section_scaling_factor(suppression_factor * nquark /
3187  (3.0 * nbaryon));
3188  }
3189 }
3190 
3191 std::pair<int, int> StringProcess::find_leading(int nq1, int nq2,
3192  ParticleList &list) {
3193  assert(list.size() >= 2);
3194  int end = list.size() - 1;
3195  int i1, i2;
3196  for (i1 = 0;
3197  i1 <= end && !list[i1].pdgcode().contains_enough_valence_quarks(nq1);
3198  i1++) {
3199  }
3200  for (i2 = end;
3201  i2 >= 0 && !list[i2].pdgcode().contains_enough_valence_quarks(nq2);
3202  i2--) {
3203  }
3204  std::pair<int, int> indices(i1, i2);
3205  return indices;
3206 }
3207 
3209  ParticleList &outgoing_particles,
3210  const ThreeVector &evecLong,
3211  double suppression_factor) {
3212  // Set each particle's cross section scaling factor to 0 first
3213  for (ParticleData &data : outgoing_particles) {
3214  data.set_cross_section_scaling_factor(0.0);
3215  }
3216  // sort outgoing particles according to the longitudinal velocity
3217  std::sort(outgoing_particles.begin(), outgoing_particles.end(),
3218  [&](ParticleData i, ParticleData j) {
3219  return i.momentum().velocity() * evecLong >
3220  j.momentum().velocity() * evecLong;
3221  });
3222  int nq1, nq2; // number of quarks at both ends of the string
3223  switch (baryon_string) {
3224  case 0:
3225  nq1 = -1;
3226  nq2 = 1;
3227  break;
3228  case 1:
3229  nq1 = 2;
3230  nq2 = 1;
3231  break;
3232  case -1:
3233  nq1 = -2;
3234  nq2 = -1;
3235  break;
3236  default:
3237  throw std::runtime_error("string is neither mesonic nor baryonic");
3238  }
3239  // Try to find nq1 on one string end and nq2 on the other string end and the
3240  // other way around. When the leading particles are close to the string ends,
3241  // the quarks are assumed to be distributed this way.
3242  std::pair<int, int> i = find_leading(nq1, nq2, outgoing_particles);
3243  std::pair<int, int> j = find_leading(nq2, nq1, outgoing_particles);
3244  if (baryon_string == 0 && i.second - i.first < j.second - j.first) {
3245  assign_scaling_factor(nq2, outgoing_particles[j.first], suppression_factor);
3246  assign_scaling_factor(nq1, outgoing_particles[j.second],
3247  suppression_factor);
3248  } else {
3249  assign_scaling_factor(nq1, outgoing_particles[i.first], suppression_factor);
3250  assign_scaling_factor(nq2, outgoing_particles[i.second],
3251  suppression_factor);
3252  }
3253 }
3254 
3256  PdgCode pdg_mapped(0x0);
3257 
3258  if (pdg.baryon_number() == 1) { // baryon
3259  pdg_mapped = pdg.charge() > 0 ? PdgCode(pdg::p) : PdgCode(pdg::n);
3260  } else if (pdg.baryon_number() == -1) { // antibaryon
3261  pdg_mapped = pdg.charge() < 0 ? PdgCode(-pdg::p) : PdgCode(-pdg::n);
3262  } else if (pdg.is_hadron()) { // meson
3263  if (pdg.charge() >= 0) {
3264  pdg_mapped = PdgCode(pdg::pi_p);
3265  } else {
3266  pdg_mapped = PdgCode(pdg::pi_m);
3267  }
3268  } else if (pdg.is_lepton()) { // lepton
3269  pdg_mapped = pdg.charge() < 0 ? PdgCode(0x11) : PdgCode(-0x11);
3270  } else {
3271  throw std::runtime_error("StringProcess::pdg_map_for_pythia failed.");
3272  }
3273 
3274  return pdg_mapped.get_decimal();
3275 }
3276 
3277 } // namespace smash
smash::PdgCode::net_quark_number
int net_quark_number(const int quark) const
Returns the net number of quarks with given flavour number For public use, see strangeness(),...
Definition: pdgcode.cc:31
smash
Definition: action.h:24
smash::StringProcess::NpartString_
std::array< int, 2 > NpartString_
number of particles fragmented from strings
Definition: stringprocess.h:80
smash::StringProcess::NpartFinal_
int NpartFinal_
total number of final state particles
Definition: stringprocess.h:78
pow.h
smash::random::normal
double normal(const T &mean, const T &sigma)
Returns a random number drawn from a normal distribution.
Definition: random.h:250
smash::StringProcess::evecBasisAB_
std::array< ThreeVector, 3 > evecBasisAB_
Orthonormal basis vectors in the center of mass frame, where the 0th one is parallel to momentum of i...
Definition: stringprocess.h:76
smash::LOutput
static constexpr int LOutput
Definition: oscaroutput.cc:23
smash::ParticleData::momentum
const FourVector & momentum() const
Get the particle's 4-momentum.
Definition: particledata.h:152
smash::StringProcess::string_sigma_T_
double string_sigma_T_
transverse momentum spread in string fragmentation
Definition: stringprocess.h:131
smash::StringProcess::stringz_b_produce_
double stringz_b_produce_
parameter (StringZ:bLund) for the fragmentation function of other (produced) hadrons in soft non-diff...
Definition: stringprocess.h:123
smash::PdgCode::quark_content
std::array< int, 3 > quark_content() const
The return is always an array of three numbers, which are pdgcodes of quarks: 1 - d,...
Definition: pdgcode.h:566
smash::StringProcess::init
void init(const ParticleList &incoming, double tcoll)
initialization feed intial particles, time of collision and gamma factor of the center of mass.
Definition: stringprocess.cc:207
smash::StringProcess::append_final_state
int append_final_state(ParticleList &intermediate_particles, const FourVector &uString, const ThreeVector &evecLong)
compute the formation time and fill the arrays with final-state particles as described in Andersson:1...
Definition: stringprocess.cc:151
smash::StringProcess::stringz_b_leading_
double stringz_b_leading_
parameter (StringZ:bLund) for the fragmentation function of leading baryon in soft non-diffractive st...
Definition: stringprocess.h:113
smash::ParticleData
Definition: particledata.h:52
smash::random::beta_a0
T beta_a0(T xmin, T b)
Draws a random number from a beta-distribution with a = 0.
Definition: random.h:351
smash::PdgCode::baryon_number
int baryon_number() const
Definition: pdgcode.h:305
smash::PdgCode::is_nucleon
bool is_nucleon() const
Definition: pdgcode.h:321
smash::StringProcess::compose_string_parton
void compose_string_parton(bool find_forward_string, Pythia8::Event &event_intermediate, Pythia8::Event &event_hadronize)
Identify a set of partons, which are connected to form a color-neutral string, from a given PYTHIA ev...
Definition: stringprocess.cc:1267
smash::StringProcess::hard_map_
pythia_map hard_map_
Map object to contain the different pythia objects.
Definition: stringprocess.h:181
smash::StringProcess::get_resonance_from_quark
int get_resonance_from_quark(int idq1, int idq2, double mass)
Definition: stringprocess.cc:2654
smash::PdgCode::is_hadron
bool is_hadron() const
Definition: pdgcode.h:294
smash::ThreeVector::x3
double x3() const
Definition: threevector.h:173
smash::StringProcess::next_NDiffHard
bool next_NDiffHard()
Hard Non-diffractive process is based on PYTHIA 8 with partonic showers and interactions.
Definition: stringprocess.cc:520
smash::StringProcess::massB_
double massB_
mass of incoming particle B [GeV]
Definition: stringprocess.h:59
smash::StringProcess::make_string_ends
static void make_string_ends(const PdgCode &pdgcode_in, int &idq1, int &idq2, double xi)
make a random selection to determine partonic contents at the string ends.
Definition: stringprocess.cc:1715
smash::StringProcess::plab_
std::array< FourVector, 2 > plab_
momenta of incoming particles in the lab frame [GeV]
Definition: stringprocess.h:65
smash::StringProcess::set_Vec4
static Pythia8::Vec4 set_Vec4(double energy, const ThreeVector &mom)
Easy setter of Pythia Vec4 from SMASH.
Definition: stringprocess.h:865
smash::StringProcess::pythia_sigmatot_
Pythia8::SigmaTotal pythia_sigmatot_
An object to compute cross-sections.
Definition: stringprocess.h:187
smash::StringProcess::find_leading
static std::pair< int, int > find_leading(int nq1, int nq2, ParticleList &list)
Find the leading string fragments.
Definition: stringprocess.cc:3191
smash::StringProcess::pcom_
std::array< FourVector, 2 > pcom_
momenta of incoming particles in the center of mass frame [GeV]
Definition: stringprocess.h:67
smash::PdgCode::is_lepton
bool is_lepton() const
Definition: pdgcode.h:299
smash::StringProcess::sqrtsAB_
double sqrtsAB_
sqrt of Mandelstam variable s of collision [GeV]
Definition: stringprocess.h:61
smash::ThreeVector::sqr
double sqr() const
Definition: threevector.h:259
smash::ParticleData::pdgcode
PdgCode pdgcode() const
Get the pdgcode of the particle.
Definition: particledata.h:81
smash::StringProcess::prob_proton_to_d_uu_
double prob_proton_to_d_uu_
Probability of splitting a nucleon into the quark flavour it has only once and a diquark it has twice...
Definition: stringprocess.h:161
smash::StringProcess::separate_fragment_baryon_
bool separate_fragment_baryon_
Whether to use a separate fragmentation function for leading baryons.
Definition: stringprocess.h:164
smash::StringProcess::find_total_number_constituent
void find_total_number_constituent(Pythia8::Event &event_intermediate, std::array< int, 5 > &nquark_total, std::array< int, 5 > &nantiq_total)
Compute how many quarks and antiquarks we have in the system, and update the correspoing arrays with ...
Definition: stringprocess.cc:889
smash::small_number
constexpr double small_number
Physical error tolerance.
Definition: constants.h:48
smash::StringProcess::rearrange_excess
void rearrange_excess(std::array< int, 5 > &nquark_total, std::array< std::array< int, 5 >, 2 > &excess_quark, std::array< std::array< int, 5 >, 2 > &excess_antiq)
Take total number of quarks and check if the system has enough constituents that need to be converted...
Definition: stringprocess.cc:1051
smash::StringProcess::replace_constituent
void replace_constituent(Pythia8::Particle &particle, std::array< int, 5 > &excess_constituent)
Convert a partonic PYTHIA particle into the desired species and update the excess of constituents.
Definition: stringprocess.cc:804
smash::StringProcess::time_formation_const_
double time_formation_const_
constant proper time in the case of constant formation time [fm]
Definition: stringprocess.h:140
smash::StringProcess::pythia_hadron_
std::unique_ptr< Pythia8::Pythia > pythia_hadron_
PYTHIA object used in fragmentation.
Definition: stringprocess.h:184
smash::random::uniform_int
T uniform_int(T min, T max)
Definition: random.h:100
smash::StringProcess::get_hadrontype_from_quark
int get_hadrontype_from_quark(int idq1, int idq2)
Determines hadron type from valence quark constituents.
Definition: stringprocess.cc:2566
smash::ParticleData::set_4momentum
void set_4momentum(const FourVector &momentum_vector)
Set the particle's 4-momentum directly.
Definition: particledata.h:158
smash::StringProcess::set_mass_and_direction_2strings
bool set_mass_and_direction_2strings(const std::array< std::array< int, 2 >, 2 > &quarks, const std::array< FourVector, 2 > &pstr_com, std::array< double, 2 > &m_str, std::array< ThreeVector, 2 > &evec_str)
Determine string masses and directions in which strings are stretched.
Definition: stringprocess.cc:318
smash::logg
std::array< einhard::Logger<>, std::tuple_size< LogArea::AreaTuple >::value > logg
An array that stores all pre-configured Logger objects.
Definition: logging.cc:39
smash::random::beta
T beta(T a, T b)
Draws a random number from a beta-distribution, where probability density of is .
Definition: random.h:329
smash::StringProcess::PNegA_
double PNegA_
backward lightcone momentum p^{-} of incoming particle A in CM-frame [GeV]
Definition: stringprocess.h:53
smash::StringProcess::pmin_gluon_lightcone_
double pmin_gluon_lightcone_
the minimum lightcone momentum scale carried by a gluon [GeV]
Definition: stringprocess.h:82
smash::StringProcess::soft_t_form_
double soft_t_form_
factor to be multiplied to formation times in soft strings
Definition: stringprocess.h:142
smash::StringProcess::PDGcodes_
std::array< PdgCode, 2 > PDGcodes_
PdgCodes of incoming particles.
Definition: stringprocess.h:63
smash::pCM
T pCM(const T sqrts, const T mass_a, const T mass_b) noexcept
Definition: kinematics.h:79
smash::really_small
constexpr double really_small
Numerical error tolerance.
Definition: constants.h:37
smash::ParticleType::find
static const ParticleType & find(PdgCode pdgcode)
Returns the ParticleType object for the given pdgcode.
Definition: particletype.cc:99
smash::PdgCode::get_decimal
int32_t get_decimal() const
Definition: pdgcode.h:663
smash::StringProcess::PPosB_
double PPosB_
forward lightcone momentum p^{+} of incoming particle B in CM-frame [GeV]
Definition: stringprocess.h:51
random.h
angles.h
smash::StringProcess::compute_incoming_lightcone_momenta
void compute_incoming_lightcone_momenta()
compute the lightcone momenta of incoming particles where the longitudinal direction is set to be sam...
Definition: stringprocess.cc:1679
smash::StringProcess::shift_rapidity_event
void shift_rapidity_event(Pythia8::Event &event, std::array< ThreeVector, 3 > &evec_basis, double factor_yrapid, double diff_yrapid)
Shift the momentum rapidity of all particles in a given event record.
Definition: stringprocess.h:1049
smash::StringProcess::quarks_from_diquark
static void quarks_from_diquark(int diquark, int &q1, int &q2, int &deg_spin)
find two quarks from a diquark.
Definition: stringprocess.cc:1686
smash::ThreeVector
Definition: threevector.h:31
smash::StringProcess::fragment_string
int fragment_string(int idq1, int idq2, double mString, ThreeVector &evecLong, bool flip_string_ends, bool separate_fragment_baryon, ParticleList &intermediate_particles)
perform string fragmentation to determine species and momenta of hadrons by implementing PYTHIA 8....
Definition: stringprocess.cc:1763
smash::ParticleData::set_formation_time
void set_formation_time(const double &form_time)
Set the absolute formation time.
Definition: particledata.h:245
smash::StringProcess::diquark_from_quarks
static int diquark_from_quarks(int q1, int q2)
Construct diquark from two quarks.
Definition: stringprocess.cc:1702
smash::StringProcess::next_SDiff
bool next_SDiff(bool is_AB_to_AX)
Single-diffractive process is based on single pomeron exchange described in Ingelman:1984ns .
Definition: stringprocess.cc:236
smash::ParticleData::is_baryon
bool is_baryon() const
Definition: particledata.h:88
smash::StringProcess::assign_scaling_factor
static void assign_scaling_factor(int nquark, ParticleData &data, double suppression_factor)
Assign a cross section scaling factor to the given particle.
Definition: stringprocess.cc:3176
smash::StringProcess::next_DDiff
bool next_DDiff()
Double-diffractive process ( A + B -> X + X ) is similar to the single-diffractive process,...
Definition: stringprocess.cc:388
smash::FourVector::x0
double x0() const
Definition: fourvector.h:303
smash::StringProcess::strange_supp_
double strange_supp_
strange quark suppression factor
Definition: stringprocess.h:125
smash::PdgCode::charge
int charge() const
The charge of the particle.
Definition: pdgcode.h:479
smash::StringProcess::diquark_supp_
double diquark_supp_
diquark suppression factor
Definition: stringprocess.h:127
smash::StringProcess::make_orthonormal_basis
static void make_orthonormal_basis(ThreeVector &evec_polar, std::array< ThreeVector, 3 > &evec_basis)
compute three orthonormal basis vectors from unit vector in the longitudinal direction
Definition: stringprocess.cc:1630
smash::StringProcess::event_intermediate_
Pythia8::Event event_intermediate_
event record for intermediate partonic state in the hard string routine
Definition: stringprocess.h:199
smash::LPythia
static constexpr int LPythia
Definition: stringprocess.h:26
smash::StringProcess::find_junction_leg
void find_junction_leg(bool sign_color, std::vector< int > &col, Pythia8::Event &event_intermediate, Pythia8::Event &event_hadronize)
Identify partons, which are associated with junction legs, from a given PYTHIA event record.
Definition: stringprocess.cc:1457
smash::StringProcess::mass_dependent_formation_times_
bool mass_dependent_formation_times_
Whether the formation time should depend on the mass of the fragment according to Andersson:1983ia e...
Definition: stringprocess.h:156
smash::random::discrete_dist
Discrete distribution with weight given by probability vector.
Definition: random.h:258
smash::StringProcess::get_index_forward
int get_index_forward(bool find_forward, int np_end, Pythia8::Event &event)
Obtain index of the most forward or backward particle in a given PYTHIA event record.
Definition: stringprocess.h:754
smash::StringProcess::pdg_map_for_pythia
static int pdg_map_for_pythia(PdgCode &pdg)
Take pdg code and map onto particle specie which can be handled by PYTHIA.
Definition: stringprocess.cc:3255
smash::StringProcess::popcorn_rate_
double popcorn_rate_
popcorn rate
Definition: stringprocess.h:129
smash::PdgCode
Definition: pdgcode.h:108
smash::StringProcess::PNegB_
double PNegB_
backward lightcone momentum p^{-} of incoming particle B in CM-frame [GeV]
Definition: stringprocess.h:55
smash::StringProcess::convert_KaonLS
static void convert_KaonLS(int &pythia_id)
convert Kaon-L or Kaon-S into K0 or Anti-K0
Definition: stringprocess.h:825
stringprocess.h
smash::StringProcess::assign_all_scaling_factors
static void assign_all_scaling_factors(int baryon_string, ParticleList &outgoing_particles, const ThreeVector &evecLong, double suppression_factor)
Assign a cross section scaling factor to all outgoing particles.
Definition: stringprocess.cc:3208
smash::StringProcess::pow_fquark_beta_
double pow_fquark_beta_
parameter for the quark distribution function
Definition: stringprocess.h:97
smash::FourVector::velocity
ThreeVector velocity() const
Get the velocity (3-vector divided by zero component).
Definition: fourvector.h:323
smash::StringProcess::stringz_a_produce_
double stringz_a_produce_
parameter (StringZ:aLund) for the fragmentation function of other (produced) hadrons in soft non-diff...
Definition: stringprocess.h:118
smash::StringProcess::find_excess_constituent
static void find_excess_constituent(PdgCode &pdg_actual, PdgCode &pdg_mapped, std::array< int, 5 > &excess_quark, std::array< int, 5 > &excess_antiq)
Compare the valence quark contents of the actual and mapped hadrons and evaluate how many more consti...
Definition: stringprocess.cc:770
smash::StringProcess::sigma_qperp_
double sigma_qperp_
Transverse momentum spread of the excited strings.
Definition: stringprocess.h:103
smash::ParticleData::set_cross_section_scaling_factor
void set_cross_section_scaling_factor(const double &xsec_scal)
Set the particle's initial cross_section_scaling_factor.
Definition: particledata.h:287
smash::StringProcess::common_setup_pythia
void common_setup_pythia(Pythia8::Pythia *pythia_in, double strange_supp, double diquark_supp, double popcorn_rate, double stringz_a, double stringz_b, double string_sigma_T)
Common setup of PYTHIA objects for soft and hard string routines.
Definition: stringprocess.cc:87
kinematics.h
smash::StringProcess::splitting_gluon_qqbar
bool splitting_gluon_qqbar(Pythia8::Event &event_intermediate, std::array< int, 5 > &nquark_total, std::array< int, 5 > &nantiq_total, bool sign_constituent, std::array< std::array< int, 5 >, 2 > &excess_constituent)
Take total number of quarks and check if the system has enough constituents that need to be converted...
Definition: stringprocess.cc:918
smash::StringProcess::ucomAB_
FourVector ucomAB_
velocity four vector of the center of mass in the lab frame
Definition: stringprocess.h:69
smash::pow_int
constexpr T pow_int(const T base, unsigned const exponent)
Efficient template for calculating integer powers using squaring.
Definition: pow.h:23
smash::ThreeVector::abs
double abs() const
Definition: threevector.h:261
smash::StringProcess::reorient
static FourVector reorient(Pythia8::Particle &particle, std::array< ThreeVector, 3 > &evec_basis)
compute the four-momentum properly oriented in the lab frame.
Definition: stringprocess.h:880
smash::random::power
T power(T n, T xMin, T xMax)
Draws a random number according to a power-law distribution ~ x^n.
Definition: random.h:203
smash::StringProcess::sample_zLund
static double sample_zLund(double a, double b, double mTrn)
Sample lightcone momentum fraction according to the LUND fragmentation function.
Definition: stringprocess.cc:2845
smash::StringProcess::pythia_stringflav_
Pythia8::StringFlav pythia_stringflav_
An object for the flavor selection in string fragmentation in the case of separate fragmentation func...
Definition: stringprocess.h:193
smash::StringProcess::additional_xsec_supp_
double additional_xsec_supp_
additional cross-section suppression factor to take coherence effect into account.
Definition: stringprocess.h:138
smash::StringProcess::make_final_state_2strings
bool make_final_state_2strings(const std::array< std::array< int, 2 >, 2 > &quarks, const std::array< FourVector, 2 > &pstr_com, const std::array< double, 2 > &m_str, const std::array< ThreeVector, 2 > &evec_str, bool flip_string_ends, bool separate_fragment_baryon)
Prepare kinematics of two strings, fragment them and append to final_state.
Definition: stringprocess.cc:355
smash::StringProcess::remake_kinematics_fragments
bool remake_kinematics_fragments(Pythia8::Event &event_fragments, std::array< ThreeVector, 3 > &evec_basis, double ppos_string, double pneg_string, double QTrx_string, double QTry_string, double QTrx_add_pos, double QTry_add_pos, double QTrx_add_neg, double QTry_add_neg)
Definition: stringprocess.cc:2877
smash::StringProcess::append_intermediate_list
static bool append_intermediate_list(int pdgid, FourVector momentum, ParticleList &intermediate_particles)
append new particle from PYTHIA to a specific particle list
Definition: stringprocess.h:805
smash::StringProcess::compose_string_junction
void compose_string_junction(bool &find_forward_string, Pythia8::Event &event_intermediate, Pythia8::Event &event_hadronize)
Identify a set of partons and junction(s), which are connected to form a color-neutral string,...
Definition: stringprocess.cc:1354
smash::StringProcess::stringz_a_leading_
double stringz_a_leading_
parameter (StringZ:aLund) for the fragmentation function of leading baryon in soft non-diffractive st...
Definition: stringprocess.h:108
smash::FourVector
Definition: fourvector.h:33
smash::StringProcess::time_collision_
double time_collision_
time of collision in the computational frame [fm]
Definition: stringprocess.h:144
smash::StringProcess::vcomAB_
ThreeVector vcomAB_
velocity three vector of the center of mass in the lab frame
Definition: stringprocess.h:71
smash::StringProcess::next_BBbarAnn
bool next_BBbarAnn()
Baryon-antibaryon annihilation process Based on what UrQMD Bass:1998ca , Bleicher:1999xi does,...
Definition: stringprocess.cc:1519
smash::StringProcess::PPosA_
double PPosA_
forward lightcone momentum p^{+} of incoming particle A in CM-frame [GeV]
Definition: stringprocess.h:49
smash::pdg::p
constexpr int p
Proton.
Definition: pdgcode_constants.h:28
smash::PdgCode::is_baryon
bool is_baryon() const
Definition: pdgcode.h:315
smash::random::uniform
T uniform(T min, T max)
Definition: random.h:88
smash::StringProcess::pow_fgluon_beta_
double pow_fgluon_beta_
parameter for the gluon distribution function
Definition: stringprocess.h:87
smash::FourVector::lorentz_boost
FourVector lorentz_boost(const ThreeVector &v) const
Returns the FourVector boosted with velocity v.
Definition: fourvector.cc:16
smash::pdg::n
constexpr int n
Neutron.
Definition: pdgcode_constants.h:30
smash::StringProcess::make_lightcone_final_two
bool make_lightcone_final_two(bool separate_fragment_hadron, double ppos_string, double pneg_string, double mTrn_had_forward, double mTrn_had_backward, double &ppos_had_forward, double &ppos_had_backward, double &pneg_had_forward, double &pneg_had_backward)
Determines lightcone momenta of two final hadrons fragmented from a string in the same way as StringF...
Definition: stringprocess.cc:2780
smash::StringProcess::StringProcess
StringProcess(double string_tension, double time_formation, double gluon_beta, double gluon_pmin, double quark_alpha, double quark_beta, double strange_supp, double diquark_supp, double sigma_perp, double stringz_a_leading, double stringz_b_leading, double stringz_a, double stringz_b, double string_sigma_T, double factor_t_form, bool mass_dependent_formation_times, double prob_proton_to_d_uu, bool separate_fragment_baryon, double popcorn_rate)
Constructor, initializes pythia.
Definition: stringprocess.cc:21
smash::StringProcess::pow_fquark_alpha_
double pow_fquark_alpha_
parameter for the quark distribution function
Definition: stringprocess.h:92
smash::StringProcess::kappa_tension_string_
double kappa_tension_string_
string tension [GeV/fm]
Definition: stringprocess.h:133
smash::pdg::pi_m
constexpr int pi_m
π⁻.
Definition: pdgcode_constants.h:66
smash::StringProcess::restore_constituent
bool restore_constituent(Pythia8::Event &event_intermediate, std::array< std::array< int, 5 >, 2 > &excess_quark, std::array< std::array< int, 5 >, 2 > &excess_antiq)
Take the intermediate partonic state from PYTHIA event with mapped hadrons and convert constituents i...
Definition: stringprocess.cc:1108
smash::kaon_mass
constexpr double kaon_mass
Kaon mass in GeV.
Definition: constants.h:69
smash::StringProcess::fragment_off_hadron
int fragment_off_hadron(bool from_forward, bool separate_fragment_baryon, std::array< ThreeVector, 3 > &evec_basis, double &ppos_string, double &pneg_string, double &QTrx_string_pos, double &QTrx_string_neg, double &QTry_string_pos, double &QTry_string_neg, Pythia8::FlavContainer &flav_string_pos, Pythia8::FlavContainer &flav_string_neg, std::vector< int > &pdgid_frag, std::vector< FourVector > &momentum_frag)
Fragment one hadron from a given string configuration if the string mass is above threshold (given by...
Definition: stringprocess.cc:2235
smash::maximum_rndm_seed_in_pythia
constexpr int maximum_rndm_seed_in_pythia
The maximum value of the random seed used in PYTHIA.
Definition: constants.h:103
smash::pion_mass
constexpr double pion_mass
Pion mass in GeV.
Definition: constants.h:62
smash::pdg::pi_p
constexpr int pi_p
π⁺.
Definition: pdgcode_constants.h:62
smash::FourVector::threevec
ThreeVector threevec() const
Definition: fourvector.h:319
smash::StringProcess::final_state_
ParticleList final_state_
final state array which must be accessed after the collision
Definition: stringprocess.h:170
smash::StringProcess::next_NDiffSoft
bool next_NDiffSoft()
Soft Non-diffractive process is modelled in accordance with dual-topological approach Capella:1978ig ...
Definition: stringprocess.cc:443
smash::ParticleType::list_all
static const ParticleTypeList & list_all()
Definition: particletype.cc:51
smash::PdgCode::is_meson
bool is_meson() const
Definition: pdgcode.h:318
smash::StringProcess::massA_
double massA_
mass of incoming particle A [GeV]
Definition: stringprocess.h:57
smash::pCM_sqr
T pCM_sqr(const T sqrts, const T mass_a, const T mass_b) noexcept
Definition: kinematics.h:91