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