20 static constexpr
int LOutput = LogArea::Output::id;
23 double string_tension,
double time_formation,
double gluon_beta,
24 double gluon_pmin,
double quark_alpha,
double quark_beta,
25 double strange_supp,
double diquark_supp,
double sigma_perp,
26 double stringz_a_leading,
double stringz_b_leading,
double stringz_a,
27 double stringz_b,
double string_sigma_T,
double factor_t_form,
28 bool mass_dependent_formation_times,
double prob_proton_to_d_uu,
29 bool separate_fragment_baryon,
double popcorn_rate,
bool use_monash_tune)
30 : pmin_gluon_lightcone_(gluon_pmin),
31 pow_fgluon_beta_(gluon_beta),
32 pow_fquark_alpha_(quark_alpha),
33 pow_fquark_beta_(quark_beta),
34 sigma_qperp_(sigma_perp),
35 stringz_a_leading_(stringz_a_leading),
36 stringz_b_leading_(stringz_b_leading),
37 stringz_a_produce_(stringz_a),
38 stringz_b_produce_(stringz_b),
39 strange_supp_(strange_supp),
40 diquark_supp_(diquark_supp),
41 popcorn_rate_(popcorn_rate),
42 string_sigma_T_(string_sigma_T),
43 kappa_tension_string_(string_tension),
44 additional_xsec_supp_(0.7),
45 time_formation_const_(time_formation),
46 soft_t_form_(factor_t_form),
48 mass_dependent_formation_times_(mass_dependent_formation_times),
49 prob_proton_to_d_uu_(prob_proton_to_d_uu),
50 separate_fragment_baryon_(separate_fragment_baryon),
51 use_monash_tune_(use_monash_tune) {
53 pythia_hadron_ = std::make_unique<Pythia8::Pythia>(PYTHIA_XML_DIR,
false);
57 popcorn_rate, stringz_a, stringz_b, string_sigma_T);
82 for (
int imu = 0; imu < 3; imu++) {
92 double popcorn_rate,
double stringz_a,
94 double string_sigma_T) {
96 pythia_in->readString(
"ParticleData:modeBreitWigner = 4");
99 pythia_in->readString(
"MultipartonInteractions:pTmin = 1.5");
100 pythia_in->readString(
"MultipartonInteractions:nSample = 10000");
102 pythia_in->readString(
"StringPT:sigma = " + std::to_string(string_sigma_T));
104 pythia_in->readString(
"StringFlav:probQQtoQ = " +
105 std::to_string(diquark_supp));
107 pythia_in->readString(
"StringFlav:probStoUD = " +
108 std::to_string(strange_supp));
109 pythia_in->readString(
"StringFlav:popcornRate = " +
110 std::to_string(popcorn_rate));
112 pythia_in->readString(
"StringZ:aLund = " + std::to_string(stringz_a));
113 pythia_in->readString(
"StringZ:bLund = " + std::to_string(stringz_b));
116 pythia_in->readString(
"PDF:pSet = 13");
117 pythia_in->readString(
"PDF:pSetB = 13");
118 pythia_in->readString(
"PDF:piSet = 1");
119 pythia_in->readString(
"PDF:piSetB = 1");
120 pythia_in->readString(
"Beams:idA = 2212");
121 pythia_in->readString(
"Beams:idB = 2212");
122 pythia_in->readString(
"Beams:eCM = 10.");
125 pythia_in->readString(
"Random:setSeed = on");
127 pythia_in->readString(
"Print:quiet = on");
129 pythia_in->readString(
"HadronLevel:Decay = off");
132 int pdgid = ptype.pdgcode().get_decimal();
133 double mass_pole = ptype.mass();
134 double width_pole = ptype.width_at_pole();
136 if (pythia_in->particleData.isParticle(pdgid)) {
138 pythia_in->particleData.m0(pdgid, mass_pole);
139 pythia_in->particleData.mWidth(pdgid, width_pole);
140 }
else if (pdgid == 310 || pdgid == 130) {
142 pythia_in->particleData.m0(pdgid,
kaon_mass);
143 pythia_in->particleData.mWidth(pdgid, 0.);
148 pythia_in->readString(
"Check:epTolErr = 1e-6");
149 pythia_in->readString(
"Check:epTolWarn = 1e-8");
151 pythia_in->readString(
"Tune:ee = 7");
152 pythia_in->readString(
"Tune:pp = 14");
165 bstring += data.pdgcode().baryon_number();
178 for (
int i = 0; i < nfrag; i++) {
179 ThreeVector velocity = intermediate_particles[i].momentum().velocity();
180 double gamma = 1. / intermediate_particles[i].inverse_gamma();
183 intermediate_particles[i].momentum().
lorentz_boost(-vstring);
184 intermediate_particles[i].set_4momentum(momentum);
188 double tau_prod = M_SQRT2 * intermediate_particles[i].effective_mass() /
190 double t_prod = tau_prod * gamma;
194 fragment_position = fragment_position.
lorentz_boost(-vstring);
196 intermediate_particles[i].set_slow_formation_times(
201 double gamma_factor = 1.0 / std::sqrt(1 - (v_calc).sqr());
202 intermediate_particles[i].set_slow_formation_times(
216 massA_ = incoming[0].effective_mass();
217 massB_ = incoming[1].effective_mass();
219 plab_[0] = incoming[0].momentum();
220 plab_[1] = incoming[1].momentum();
253 double QTrn, QTrx, QTry;
254 double pabscomHX_sqr, massX;
263 if (mstrMin > mstrMax) {
269 QTrn = std::sqrt(QTrx * QTrx + QTry * QTry);
276 const bool foundPabsX = pabscomHX_sqr > QTrn * QTrn;
281 double sign_direction = is_AB_to_AX ? 1. : -1.;
285 (
evecBasisAB_[0] * std::sqrt(pabscomHX_sqr - QTrn * QTrn) +
287 const FourVector pstrHcom(std::sqrt(pabscomHX_sqr + massH * massH),
289 const FourVector pstrXcom(std::sqrt(pabscomHX_sqr + massX * massX),
297 is_AB_to_AX ?
pcom_[1].threevec() :
pcom_[0].threevec();
302 ParticleList new_intermediate_particles;
304 new_intermediate_particles);
325 const std::array<std::array<int, 2>, 2> &quarks,
326 const std::array<FourVector, 2> &pstr_com, std::array<double, 2> &m_str,
327 std::array<ThreeVector, 2> &evec_str) {
328 std::array<bool, 2> found_mass;
329 for (
int i = 0; i < 2; i++) {
330 found_mass[i] =
false;
332 m_str[i] = pstr_com[i].sqr();
333 m_str[i] = (m_str[i] > 0.) ? std::sqrt(m_str[i]) : 0.;
334 const double threshold =
pythia_hadron_->particleData.m0(quarks[i][0]) +
337 if (m_str[i] > threshold) {
338 found_mass[i] =
true;
358 return found_mass[0] && found_mass[1];
362 const std::array<std::array<int, 2>, 2> &quarks,
363 const std::array<FourVector, 2> &pstr_com,
364 const std::array<double, 2> &m_str,
365 const std::array<ThreeVector, 2> &evec_str,
bool flip_string_ends,
366 bool separate_fragment_baryon) {
367 const std::array<FourVector, 2> ustr_com = {pstr_com[0] / m_str[0],
368 pstr_com[1] / m_str[1]};
369 for (
int i = 0; i < 2; i++) {
370 ParticleList new_intermediate_particles;
375 int nfrag =
fragment_string(quarks[i][0], quarks[i][1], m_str[i], evec,
376 flip_string_ends, separate_fragment_baryon,
377 new_intermediate_particles);
400 std::array<std::array<int, 2>, 2> quarks;
401 std::array<FourVector, 2> pstr_com;
402 std::array<double, 2> m_str;
403 std::array<ThreeVector, 2> evec_str;
413 const double xfracA =
415 const double xfracB =
420 const double QTrn = std::sqrt(QTrx * QTrx + QTry * QTry);
422 const double QPos = -QTrn * QTrn / (2. * xfracB *
PNegB_);
423 const double QNeg = QTrn * QTrn / (2. * xfracA *
PPosA_);
437 const bool found_masses =
442 const bool flip_string_ends =
true;
444 quarks, pstr_com, m_str, evec_str, flip_string_ends,
false);
455 std::array<std::array<int, 2>, 2> quarks;
456 std::array<FourVector, 2> pstr_com;
457 std::array<double, 2> m_str;
458 std::array<ThreeVector, 2> evec_str;
461 int idqA1, idqA2, idqB1, idqB2;
465 const int bar_a =
PDGcodes_[0].baryon_number(),
468 (bar_a == 0 && bar_b == 1) ||
469 (bar_a == 0 && bar_b == 0)) {
470 quarks[0][0] = idqB1;
471 quarks[0][1] = idqA2;
472 quarks[1][0] = idqA1;
473 quarks[1][1] = idqB2;
474 }
else if (((bar_a == 0) && (bar_b == -1)) ||
477 quarks[0][0] = idqA1;
478 quarks[0][1] = idqB2;
479 quarks[1][0] = idqB1;
480 quarks[1][1] = idqA2;
482 std::stringstream ss;
483 ss <<
" StringProcess::next_NDiff : baryonA = " << bar_a
484 <<
", baryonB = " << bar_b;
485 throw std::runtime_error(ss.str());
493 const double QTrn = std::sqrt(QTrx * QTrx + QTry * QTry);
495 const double QPos = -QTrn * QTrn / (2. * xfracB *
PNegB_);
496 const double QNeg = QTrn * QTrn / (2. * xfracA *
PPosA_);
497 const double dPPos = -xfracA *
PPosA_ - QPos;
498 const double dPNeg = xfracB *
PNegB_ - QNeg;
505 m_str[0] = pstr_com[0].sqr();
513 const bool found_masses =
518 const bool flip_string_ends =
false;
533 std::array<int, 2> pdg_for_pythia;
534 std::array<std::array<int, 5>, 2> excess_quark;
535 std::array<std::array<int, 5>, 2> excess_antiq;
536 for (
int i = 0; i < 2; i++) {
537 for (
int j = 0; j < 5; j++) {
538 excess_quark[i][j] = 0;
539 excess_antiq[i][j] = 0;
545 " is mapped onto ", pdg_for_pythia[i]);
547 PdgCode pdgcode_for_pythia(std::to_string(pdg_for_pythia[i]));
552 logg[
LPythia].debug(
" excess_quark[", i,
"] = (", excess_quark[i][0],
553 ", ", excess_quark[i][1],
", ", excess_quark[i][2],
554 ", ", excess_quark[i][3],
", ", excess_quark[i][4],
556 logg[
LPythia].debug(
" excess_antiq[", i,
"] = (", excess_antiq[i][0],
557 ", ", excess_antiq[i][1],
", ", excess_antiq[i][2],
558 ", ", excess_antiq[i][3],
", ", excess_antiq[i][4],
562 std::pair<int, int> idAB{pdg_for_pythia[0], pdg_for_pythia[1]};
567 hard_map_[idAB] = std::make_unique<Pythia8::Pythia>(PYTHIA_XML_DIR,
false);
568 hard_map_[idAB]->readString(
"SoftQCD:nonDiffractive = on");
569 hard_map_[idAB]->readString(
"MultipartonInteractions:pTmin = 1.5");
570 hard_map_[idAB]->readString(
"HadronLevel:all = off");
576 hard_map_[idAB]->settings.flag(
"Beams:allowVariableEnergy",
true);
578 hard_map_[idAB]->settings.mode(
"Beams:idA", idAB.first);
579 hard_map_[idAB]->settings.mode(
"Beams:idB", idAB.second);
582 logg[
LPythia].debug(
"Pythia object initialized with ", pdg_for_pythia[0],
583 " + ", pdg_for_pythia[1],
" at CM energy [GeV] ",
587 throw std::runtime_error(
"Pythia failed to initialize.");
593 logg[
LPythia].debug(
"hard_map_[", idAB.first,
"][", idAB.second,
594 "] : rndm is initialized with seed ", seed_new);
603 bool final_state_success =
hard_map_[idAB]->next();
604 logg[
LPythia].debug(
"Pythia final state computed, success = ",
605 final_state_success);
606 if (!final_state_success) {
610 ParticleList new_intermediate_particles;
611 ParticleList new_non_hadron_particles;
613 Pythia8::Vec4 pSum = 0.;
618 for (
int i = 0; i <
hard_map_[idAB]->event.size(); i++) {
619 if (
hard_map_[idAB]->event[i].isFinal()) {
620 const int pdgid =
hard_map_[idAB]->event[i].id();
621 Pythia8::Vec4 pquark =
hard_map_[idAB]->event[i].p();
622 const double mass =
hard_map_[idAB]->particleData.m0(pdgid);
624 const int status =
hard_map_[idAB]->event[i].status();
625 const int color =
hard_map_[idAB]->event[i].col();
626 const int anticolor =
hard_map_[idAB]->event[i].acol();
634 for (
int i = 0; i <
hard_map_[idAB]->event.sizeJunction(); i++) {
635 const int kind =
hard_map_[idAB]->event.kindJunction(i);
636 std::array<int, 3> col;
637 for (
int j = 0; j < 3; j++) {
638 col[j] =
hard_map_[idAB]->event.colJunction(i, j);
650 bool correct_constituents =
652 if (!correct_constituents) {
653 logg[
LPythia].debug(
"failed to find correct partonic constituents.");
659 while (ipart < npart) {
663 !
hard_map_[idAB]->particleData.isOctetHadron(pdgid)) {
664 logg[
LPythia].debug(
"PDG ID from Pythia: ", pdgid);
666 logg[
LPythia].debug(
"4-momentum from Pythia: ", momentum);
671 " does not exist in ParticleType - start over.");
672 final_state_success =
false;
681 bool hadronize_success =
false;
682 bool find_forward_string =
true;
683 logg[
LPythia].debug(
"Hard non-diff: partonic process gives ",
690 logg[
LPythia].debug(
" Dummy event in hard string routine failed.");
691 hadronize_success =
false;
708 logg[
LPythia].debug(
"Pythia hadronized, success = ", hadronize_success);
710 new_intermediate_particles.clear();
711 if (hadronize_success) {
712 for (
int i = 0; i < event_hadron.size(); i++) {
713 if (event_hadron[i].isFinal()) {
714 int pythia_id = event_hadron[i].id();
715 logg[
LPythia].debug(
"PDG ID from Pythia: ", pythia_id);
728 logg[
LPythia].debug(
"4-momentum from Pythia: ", momentum);
729 logg[
LPythia].debug(
"appending the particle ", pythia_id,
730 " to the intermediate particle list.");
731 bool found_ptype =
false;
732 if (event_hadron[i].isHadron()) {
734 new_intermediate_particles);
737 new_non_hadron_particles);
741 " does not exist in ParticleType - start over.");
742 hadronize_success =
false;
750 if (!hadronize_success) {
759 find_forward_string = !find_forward_string;
762 if (hadronize_success) {
765 data.set_cross_section_scaling_factor(1.);
773 return hadronize_success;
778 std::array<int, 5> &excess_quark,
779 std::array<int, 5> &excess_antiq) {
782 std::array<int, 3> qcontent_actual = pdg_actual.
quark_content();
783 std::array<int, 3> qcontent_mapped = pdg_mapped.
quark_content();
785 excess_quark = {0, 0, 0, 0, 0};
786 excess_antiq = {0, 0, 0, 0, 0};
787 for (
int i = 0; i < 3; i++) {
788 if (qcontent_actual[i] > 0) {
789 int j = qcontent_actual[i] - 1;
790 excess_quark[j] += 1;
793 if (qcontent_mapped[i] > 0) {
794 int j = qcontent_mapped[i] - 1;
795 excess_quark[j] -= 1;
798 if (qcontent_actual[i] < 0) {
799 int j = std::abs(qcontent_actual[i]) - 1;
800 excess_antiq[j] += 1;
803 if (qcontent_mapped[i] < 0) {
804 int j = std::abs(qcontent_mapped[i]) - 1;
805 excess_antiq[j] -= 1;
811 Pythia8::Particle &particle, std::array<int, 5> &excess_constituent) {
813 if (!particle.isQuark() && !particle.isDiquark()) {
818 const std::array<int, 5> excess_null = {0, 0, 0, 0, 0};
819 if (excess_constituent == excess_null) {
824 std::array<int, 2> pdgid = {0, 0};
827 if (particle.isQuark()) {
829 pdgid[0] = particle.id();
830 }
else if (particle.isDiquark()) {
835 for (
int iq = 0; iq < nq; iq++) {
836 int jq = std::abs(pdgid[iq]) - 1;
838 std::vector<int> k_found;
841 if (excess_constituent[jq] < 0) {
842 for (
int k = 0; k < 5; k++) {
844 if (k != jq && excess_constituent[k] > 0) {
845 k_found.push_back(k);
851 if (k_found.size() > 0) {
854 k_select = k_found[l];
857 pdgid[iq] = pdgid[iq] > 0 ? k_select + 1 : -(k_select + 1);
858 excess_constituent[jq] += 1;
859 excess_constituent[k_select] -= 1;
864 if (particle.isQuark()) {
865 pdgid_new = pdgid[0];
866 }
else if (particle.isDiquark()) {
867 if (std::abs(pdgid[0]) < std::abs(pdgid[1])) {
868 std::swap(pdgid[0], pdgid[1]);
871 pdgid_new = std::abs(pdgid[0]) * 1000 + std::abs(pdgid[1]) * 100;
872 if (std::abs(pdgid[0]) == std::abs(pdgid[1])) {
875 pdgid_new += spin_deg;
878 if (particle.id() < 0) {
882 logg[
LPythia].debug(
" parton id = ", particle.id(),
" is converted to ",
886 Pythia8::Vec4 pquark = particle.p();
888 double e_new = std::sqrt(mass_new * mass_new + pquark.pAbs() * pquark.pAbs());
890 particle.id(pdgid_new);
892 particle.m(mass_new);
896 Pythia8::Event &event_intermediate, std::array<int, 5> &nquark_total,
897 std::array<int, 5> &nantiq_total) {
898 for (
int iflav = 0; iflav < 5; iflav++) {
899 nquark_total[iflav] = 0;
900 nantiq_total[iflav] = 0;
903 for (
int ip = 1; ip < event_intermediate.size(); ip++) {
904 if (!event_intermediate[ip].isFinal()) {
907 const int pdgid = event_intermediate[ip].id();
910 for (
int iflav = 0; iflav < 5; iflav++) {
911 nquark_total[iflav] +=
916 for (
int iflav = 0; iflav < 5; iflav++) {
917 nantiq_total[iflav] +=
pythia_hadron_->particleData.nQuarksInCode(
918 std::abs(pdgid), iflav + 1);
925 Pythia8::Event &event_intermediate, std::array<int, 5> &nquark_total,
926 std::array<int, 5> &nantiq_total,
bool sign_constituent,
927 std::array<std::array<int, 5>, 2> &excess_constituent) {
928 Pythia8::Vec4 pSum = event_intermediate[0].p();
934 for (
int iflav = 0; iflav < 5; iflav++) {
941 excess_constituent[0][iflav] + excess_constituent[1][iflav];
942 if (sign_constituent) {
943 nquark_final += nquark_total[iflav];
945 nquark_final += nantiq_total[iflav];
950 bool enough_quark = nquark_final >= 0;
954 logg[
LPythia].debug(
" not enough constituents with flavor ", iflav + 1,
955 " : try to split a gluon to qqbar.");
956 for (
int ic = 0; ic < std::abs(nquark_final); ic++) {
960 if (excess_constituent[0][iflav] < 0) {
969 for (
int ip = 2; ip < event_intermediate.size(); ip++) {
970 if (!event_intermediate[ip].isFinal() ||
971 !event_intermediate[ip].isGluon()) {
975 const double y_gluon_current = event_intermediate[ip].y();
976 const double y_gluon_forward = event_intermediate[iforward].y();
977 if ((ih_mod == 0 && y_gluon_current > y_gluon_forward) ||
978 (ih_mod == 1 && y_gluon_current < y_gluon_forward)) {
983 if (!event_intermediate[iforward].isGluon()) {
984 logg[
LPythia].debug(
"There is no gluon to split into qqbar.");
989 Pythia8::Vec4 pgluon = event_intermediate[iforward].p();
991 const int pdgid = iflav + 1;
993 const int status = event_intermediate[iforward].status();
997 const int col = event_intermediate[iforward].col();
998 const int acol = event_intermediate[iforward].acol();
1001 std::array<double, 2> px_quark;
1002 std::array<double, 2> py_quark;
1003 std::array<double, 2> pz_quark;
1005 std::array<double, 2> e_quark;
1007 std::array<Pythia8::Vec4, 2> pquark;
1009 const double sigma_qt_frag =
pythia_hadron_->parm(
"StringPT:sigma");
1014 for (
int isign = 0; isign < 2; isign++) {
1018 px_quark[isign] = 0.5 * pgluon.px() + (isign == 0 ? 1. : -1.) * qx;
1019 py_quark[isign] = 0.5 * pgluon.py() + (isign == 0 ? 1. : -1.) * qy;
1020 pz_quark[isign] = 0.5 * pgluon.pz();
1022 std::sqrt(mass * mass + px_quark[isign] * px_quark[isign] +
1023 py_quark[isign] * py_quark[isign] +
1024 pz_quark[isign] * pz_quark[isign]);
1025 pquark[isign] = Pythia8::Vec4(px_quark[isign], py_quark[isign],
1026 pz_quark[isign], e_quark[isign]);
1031 pSum += pquark[0] + pquark[1] - pgluon;
1033 event_intermediate.append(pdgid, status, col, 0, pquark[0], mass);
1034 event_intermediate.append(-pdgid, status, 0, acol, pquark[1], mass);
1036 event_intermediate.remove(iforward, iforward);
1038 logg[
LPythia].debug(
" gluon at iforward = ", iforward,
1039 " is splitted into ", pdgid,
",", -pdgid,
1043 nquark_total[iflav] += 1;
1044 nantiq_total[iflav] += 1;
1051 event_intermediate[0].p(pSum);
1052 event_intermediate[0].m(pSum.mCalc());
1058 std::array<int, 5> &nquark_total,
1059 std::array<std::array<int, 5>, 2> &excess_quark,
1060 std::array<std::array<int, 5>, 2> &excess_antiq) {
1061 for (
int iflav = 0; iflav < 5; iflav++) {
1068 nquark_total[iflav] + excess_quark[0][iflav] + excess_quark[1][iflav];
1072 bool enough_quark = nquark_final >= 0;
1074 if (!enough_quark) {
1075 logg[
LPythia].debug(
" not enough constituents with flavor ", iflav + 1,
1076 " : try to modify excess of constituents.");
1077 for (
int ic = 0; ic < std::abs(nquark_final); ic++) {
1081 if (excess_quark[0][iflav] < 0) {
1089 excess_quark[ih_mod][iflav] += 1;
1090 excess_antiq[ih_mod][iflav] += 1;
1097 for (
int jflav = 0; jflav < 5; jflav++) {
1099 if (jflav != iflav && excess_quark[ih_mod][jflav] > 0) {
1102 excess_quark[ih_mod][jflav] -= 1;
1103 excess_antiq[ih_mod][jflav] -= 1;
1115 Pythia8::Event &event_intermediate,
1116 std::array<std::array<int, 5>, 2> &excess_quark,
1117 std::array<std::array<int, 5>, 2> &excess_antiq) {
1118 Pythia8::Vec4 pSum = event_intermediate[0].p();
1119 const double energy_init = pSum.e();
1120 logg[
LPythia].debug(
" initial total energy [GeV] : ", energy_init);
1123 std::array<int, 5> nquark_total;
1124 std::array<int, 5> nantiq_total;
1129 event_intermediate, nquark_total, nantiq_total,
true, excess_quark);
1131 event_intermediate, nquark_total, nantiq_total,
false, excess_antiq);
1135 if (!split_for_quark || !split_for_antiq) {
1141 for (
int iflav = 0; iflav < 5; iflav++) {
1142 if (nquark_total[iflav] + excess_quark[0][iflav] + excess_quark[1][iflav] <
1144 logg[
LPythia].debug(
"Not enough quark constituents of flavor ",
1149 if (nantiq_total[iflav] + excess_antiq[0][iflav] + excess_antiq[1][iflav] <
1151 logg[
LPythia].debug(
"Not enough antiquark constituents of flavor ",
1157 for (
int ih = 0; ih < 2; ih++) {
1158 logg[
LPythia].debug(
" initial excess_quark[", ih,
"] = (",
1159 excess_quark[ih][0],
", ", excess_quark[ih][1],
", ",
1160 excess_quark[ih][2],
", ", excess_quark[ih][3],
", ",
1161 excess_quark[ih][4],
")");
1162 logg[
LPythia].debug(
" initial excess_antiq[", ih,
"] = (",
1163 excess_antiq[ih][0],
", ", excess_antiq[ih][1],
", ",
1164 excess_antiq[ih][2],
", ", excess_antiq[ih][3],
", ",
1165 excess_antiq[ih][4],
")");
1168 bool recovered_quarks =
false;
1169 while (!recovered_quarks) {
1172 std::array<bool, 2> find_forward = {
true,
false};
1173 const std::array<int, 5> excess_null = {0, 0, 0, 0, 0};
1174 std::array<int, 5> excess_total = excess_null;
1176 for (
int ih = 0; ih < 2; ih++) {
1177 int nfrag = event_intermediate.size();
1178 for (
int np_end = 0; np_end < nfrag - 1; np_end++) {
1185 pSum -= event_intermediate[iforward].p();
1187 if (event_intermediate[iforward].
id() > 0) {
1190 " excess_quark[", ih,
"] = (", excess_quark[ih][0],
", ",
1191 excess_quark[ih][1],
", ", excess_quark[ih][2],
", ",
1192 excess_quark[ih][3],
", ", excess_quark[ih][4],
")");
1196 " excess_antiq[", ih,
"] = (", excess_antiq[ih][0],
", ",
1197 excess_antiq[ih][1],
", ", excess_antiq[ih][2],
", ",
1198 excess_antiq[ih][3],
", ", excess_antiq[ih][4],
")");
1201 const int pdgid = event_intermediate[iforward].id();
1202 Pythia8::Vec4 pquark = event_intermediate[iforward].p();
1205 const int status = event_intermediate[iforward].status();
1206 const int color = event_intermediate[iforward].col();
1207 const int anticolor = event_intermediate[iforward].acol();
1210 event_intermediate.append(pdgid, status, color, anticolor, pquark,
1213 event_intermediate.remove(iforward, iforward);
1219 for (
int j = 0; j < 5; j++) {
1220 excess_total[j] += (excess_quark[ih][j] - excess_antiq[ih][j]);
1226 recovered_quarks = excess_total == excess_null;
1228 logg[
LPythia].debug(
" valence quark contents of hadons are recovered.");
1230 logg[
LPythia].debug(
" current total energy [GeV] : ", pSum.e());
1234 if (std::abs(pSum.e() - energy_init) <=
1239 double energy_current = pSum.e();
1241 for (
int i = 1; i < event_intermediate.size(); i++) {
1242 slope += event_intermediate[i].pAbs2() / event_intermediate[i].e();
1245 const double rescale_factor = 1. + (energy_init - energy_current) / slope;
1247 for (
int i = 1; i < event_intermediate.size(); i++) {
1248 const double px = rescale_factor * event_intermediate[i].px();
1249 const double py = rescale_factor * event_intermediate[i].py();
1250 const double pz = rescale_factor * event_intermediate[i].pz();
1251 const double pabs = rescale_factor * event_intermediate[i].pAbs();
1252 const double mass = event_intermediate[i].m();
1254 event_intermediate[i].px(px);
1255 event_intermediate[i].py(py);
1256 event_intermediate[i].pz(pz);
1257 event_intermediate[i].e(std::sqrt(mass * mass + pabs * pabs));
1258 pSum += event_intermediate[i].p();
1260 logg[
LPythia].debug(
" parton momenta are rescaled by factor of ",
1264 logg[
LPythia].debug(
" final total energy [GeV] : ", pSum.e());
1267 event_intermediate[0].p(pSum);
1268 event_intermediate[0].m(pSum.mCalc());
1274 Pythia8::Event &event_intermediate,
1275 Pythia8::Event &event_hadronize) {
1276 Pythia8::Vec4 pSum = 0.;
1277 event_hadronize.reset();
1281 logg[
LPythia].debug(
"Hard non-diff: iforward = ", iforward,
"(",
1282 event_intermediate[iforward].
id(),
")");
1284 pSum += event_intermediate[iforward].p();
1285 event_hadronize.append(event_intermediate[iforward]);
1287 int col_to_find = event_intermediate[iforward].acol();
1288 int acol_to_find = event_intermediate[iforward].col();
1289 event_intermediate.remove(iforward, iforward);
1290 logg[
LPythia].debug(
"Hard non-diff: event_intermediate reduces in size to ",
1291 event_intermediate.size());
1294 while (col_to_find != 0 || acol_to_find != 0) {
1295 logg[
LPythia].debug(
" col_to_find = ", col_to_find,
1296 ", acol_to_find = ", acol_to_find);
1299 for (
int i = 1; i < event_intermediate.size(); i++) {
1300 const int pdgid = event_intermediate[i].id();
1302 col_to_find != 0 && col_to_find == event_intermediate[i].col();
1304 acol_to_find != 0 && acol_to_find == event_intermediate[i].acol();
1306 logg[
LPythia].debug(
" col_to_find ", col_to_find,
" from i ", i,
"(",
1310 logg[
LPythia].debug(
" acol_to_find ", acol_to_find,
" from i ", i,
"(",
1314 if (found_col && !found_acol) {
1316 col_to_find = event_intermediate[i].acol();
1318 }
else if (!found_col && found_acol) {
1320 acol_to_find = event_intermediate[i].col();
1322 }
else if (found_col && found_acol) {
1331 event_intermediate.list();
1332 event_intermediate.listJunctions();
1333 event_hadronize.list();
1334 event_hadronize.listJunctions();
1335 if (col_to_find != 0) {
1336 logg[
LPythia].error(
"No parton with col = ", col_to_find);
1338 if (acol_to_find != 0) {
1339 logg[
LPythia].error(
"No parton with acol = ", acol_to_find);
1341 throw std::runtime_error(
"Hard string could not be identified.");
1343 pSum += event_intermediate[ifound].p();
1345 event_hadronize.append(event_intermediate[ifound]);
1347 event_intermediate.remove(ifound, ifound);
1349 "Hard non-diff: event_intermediate reduces in size to ",
1350 event_intermediate.size());
1356 event_hadronize[0].p(pSum);
1357 event_hadronize[0].m(pSum.mCalc());
1361 Pythia8::Event &event_intermediate,
1362 Pythia8::Event &event_hadronize) {
1363 event_hadronize.reset();
1371 const int kind = event_intermediate.kindJunction(0);
1372 bool sign_color = kind % 2 == 1;
1373 std::vector<int> col;
1374 for (
int j = 0; j < 3; j++) {
1375 col.push_back(event_intermediate.colJunction(0, j));
1377 event_hadronize.appendJunction(kind, col[0], col[1], col[2]);
1378 event_intermediate.eraseJunction(0);
1379 logg[
LPythia].debug(
"junction (", col[0],
", ", col[1],
", ", col[2],
1380 ") with kind ", kind,
" will be handled.");
1382 bool found_string =
false;
1383 while (!found_string) {
1386 found_string =
true;
1387 for (
unsigned int j = 0; j < col.size(); j++) {
1388 found_string = found_string && col[j] == 0;
1390 if (!found_string) {
1393 logg[
LPythia].debug(
" still has leg(s) unfinished.");
1394 sign_color = !sign_color;
1395 std::vector<int> junction_to_move;
1396 for (
int i = 0; i < event_intermediate.sizeJunction(); i++) {
1397 const int kind_new = event_intermediate.kindJunction(i);
1401 if (sign_color != (kind_new % 2 == 1)) {
1405 std::array<int, 3> col_new;
1406 for (
int k = 0; k < 3; k++) {
1407 col_new[k] = event_intermediate.colJunction(i, k);
1410 int n_legs_connected = 0;
1412 for (
unsigned int j = 0; j < col.size(); j++) {
1416 for (
int k = 0; k < 3; k++) {
1417 if (col[j] == col_new[k]) {
1418 n_legs_connected += 1;
1426 if (n_legs_connected > 0) {
1427 for (
int k = 0; k < 3; k++) {
1428 if (col_new[k] != 0) {
1429 col.push_back(col_new[k]);
1433 event_intermediate.colJunction(i, 0),
", ",
1434 event_intermediate.colJunction(i, 1),
", ",
1435 event_intermediate.colJunction(i, 2),
1436 ") with kind ", kind_new,
" will be added.");
1437 junction_to_move.push_back(i);
1443 for (
unsigned int i = 0; i < junction_to_move.size(); i++) {
1444 unsigned int imove = junction_to_move[i] - i;
1445 const int kind_add = event_intermediate.kindJunction(imove);
1446 std::array<int, 3> col_add;
1447 for (
int k = 0; k < 3; k++) {
1448 col_add[k] = event_intermediate.colJunction(imove, k);
1451 event_hadronize.appendJunction(kind_add, col_add[0], col_add[1],
1454 event_intermediate.eraseJunction(imove);
1459 Pythia8::Vec4 pSum = event_hadronize[0].p();
1460 find_forward_string = pSum.pz() > 0.;
1464 Pythia8::Event &event_intermediate,
1465 Pythia8::Event &event_hadronize) {
1466 Pythia8::Vec4 pSum = event_hadronize[0].p();
1467 for (
unsigned int j = 0; j < col.size(); j++) {
1471 bool found_leg =
false;
1472 while (!found_leg) {
1474 for (
int i = 1; i < event_intermediate.size(); i++) {
1475 const int pdgid = event_intermediate[i].id();
1476 if (sign_color && col[j] == event_intermediate[i].col()) {
1477 logg[
LPythia].debug(
" col[", j,
"] = ", col[j],
" from i ", i,
"(",
1480 col[j] = event_intermediate[i].acol();
1482 }
else if (!sign_color && col[j] == event_intermediate[i].acol()) {
1483 logg[
LPythia].debug(
" acol[", j,
"] = ", col[j],
" from i ", i,
"(",
1486 col[j] = event_intermediate[i].col();
1493 if (event_intermediate.sizeJunction() == 0) {
1494 event_intermediate.list();
1495 event_intermediate.listJunctions();
1496 event_hadronize.list();
1497 event_hadronize.listJunctions();
1498 logg[
LPythia].error(
"No parton with col = ", col[j],
1499 " connected with junction leg ", j);
1500 throw std::runtime_error(
"Hard string could not be identified.");
1503 pSum += event_intermediate[ifound].p();
1505 event_hadronize.append(event_intermediate[ifound]);
1507 event_intermediate.remove(ifound, ifound);
1509 "Hard non-diff: event_intermediate reduces in size to ",
1510 event_intermediate.size());
1520 event_hadronize[0].p(pSum);
1521 event_hadronize[0].m(pSum.mCalc());
1526 const std::array<FourVector, 2> ustrcom = {
FourVector(1., 0., 0., 0.),
1540 std::swap(baryon, antibaryon);
1542 if (baryon.
baryon_number() != 1 || antibaryon.baryon_number() != -1) {
1543 throw std::invalid_argument(
"Expected baryon-antibaryon pair.");
1547 constexpr
int n_q_types = 5;
1548 std::vector<int> qcount_bar, qcount_antibar;
1549 std::vector<int> n_combinations;
1550 bool no_combinations =
true;
1551 for (
int i = 0; i < n_q_types; i++) {
1553 qcount_antibar.push_back(-antibaryon.net_quark_number(i + 1));
1554 const int n_i = qcount_bar[i] * qcount_antibar[i];
1555 n_combinations.push_back(n_i);
1557 no_combinations =
false;
1563 if (no_combinations) {
1564 for (
int i = 0; i < 2; i++) {
1578 const int q_annihilate = discrete_distr() + 1;
1579 qcount_bar[q_annihilate - 1]--;
1580 qcount_antibar[q_annihilate - 1]--;
1583 std::vector<int> remaining_quarks, remaining_antiquarks;
1584 for (
int i = 0; i < n_q_types; i++) {
1585 for (
int j = 0; j < qcount_bar[i]; j++) {
1586 remaining_quarks.push_back(i + 1);
1588 for (
int j = 0; j < qcount_antibar[i]; j++) {
1589 remaining_antiquarks.push_back(-(i + 1));
1592 assert(remaining_quarks.size() == 2);
1593 assert(remaining_antiquarks.size() == 2);
1599 std::swap(remaining_quarks[0], remaining_quarks[1]);
1602 std::swap(remaining_antiquarks[0], remaining_antiquarks[1]);
1605 bool kin_threshold_satisfied =
true;
1606 for (
int i = 0; i < 2; i++) {
1607 const double mstr_min =
1610 if (mstr_min > mstr[i]) {
1611 kin_threshold_satisfied =
false;
1614 if (!kin_threshold_satisfied) {
1618 for (
int i = 0; i < 2; i++) {
1619 ParticleList new_intermediate_particles;
1623 fragment_string(remaining_quarks[i], remaining_antiquarks[i], mstr[i],
1624 evec,
true,
false, new_intermediate_particles);
1637 ThreeVector &evec_polar, std::array<ThreeVector, 3> &evec_basis) {
1640 if (std::abs(evec_polar.
x3()) < (1. - 1.0e-8)) {
1645 evec_basis[0] = evec_polar;
1647 theta = std::acos(evec_basis[0].x3());
1649 ex = evec_basis[0].x1();
1650 ey = evec_basis[0].x2();
1651 et = std::sqrt(ex * ex + ey * ey);
1653 phi = std::acos(ex / et);
1655 phi = -std::acos(ex / et);
1660 evec_basis[1].set_x1(std::cos(theta) * std::cos(phi));
1661 evec_basis[1].set_x2(std::cos(theta) * std::sin(phi));
1662 evec_basis[1].set_x3(-std::sin(theta));
1664 evec_basis[2].set_x1(-std::sin(phi));
1665 evec_basis[2].set_x2(std::cos(phi));
1666 evec_basis[2].set_x3(0.);
1669 if (evec_polar.
x3() > 0.) {
1680 assert(std::fabs(evec_basis[1] * evec_basis[2]) <
really_small);
1681 assert(std::fabs(evec_basis[2] * evec_basis[0]) <
really_small);
1682 assert(std::fabs(evec_basis[0] * evec_basis[1]) <
really_small);
1695 assert((std::abs(diquark) > 1000) && (std::abs(diquark) < 5510) &&
1696 (std::abs(diquark) % 100 < 10));
1699 deg_spin = std::abs(diquark) % 10;
1701 const int sign_anti = diquark > 0 ? 1 : -1;
1704 q1 = sign_anti * (std::abs(diquark) - (std::abs(diquark) % 1000)) / 1000;
1705 q2 = sign_anti * (std::abs(diquark) % 1000 - deg_spin) / 100;
1709 assert((q1 > 0 && q2 > 0) || (q1 < 0 && q2 < 0));
1710 if (std::abs(q1) < std::abs(q2)) {
1713 int diquark = std::abs(q1 * 1000 + q2 * 100);
1718 return (q1 < 0) ? -diquark : diquark;
1765 std::swap(idq1, idq2);
1771 bool separate_fragment_baryon,
1772 ParticleList &intermediate_particles) {
1774 intermediate_particles.clear();
1776 logg[
LPythia].debug(
"initial quark content for fragment_string : ", idq1,
1778 logg[
LPythia].debug(
"initial string mass (GeV) for fragment_string : ",
1781 std::array<int, 2> idqIn;
1787 std::array<double, 2> m_const;
1789 for (
int i = 0; i < 2; i++) {
1791 bstring +=
pythia_hadron_->particleData.baryonNumberType(idqIn[i]);
1795 logg[
LPythia].debug(
"baryon number of string times 3 : ", bstring);
1802 evecLong = -evecLong;
1805 if (m_const[0] + m_const[1] > mString) {
1806 throw std::runtime_error(
"String fragmentation: m1 + m2 > mString");
1808 Pythia8::Vec4 pSum = 0.;
1810 int number_of_fragments = 0;
1811 bool do_string_fragmentation =
false;
1815 double ppos_string_new, pneg_string_new;
1818 double QTrx_string_new, QTry_string_new, QTrn_string_new;
1820 double mTrn_string_new;
1822 double mass_string_new;
1826 double QTrx_add_pos, QTry_add_pos;
1829 double QTrx_add_neg, QTry_add_neg;
1841 std::array<ThreeVector, 3> evec_basis;
1844 if (separate_fragment_baryon && (std::abs(bstring) == 3) &&
1845 (mString > m_const[0] + m_const[1] + 1.)) {
1852 std::vector<int> pdgid_frag_prior;
1855 std::vector<FourVector> momentum_frag_prior;
1858 double QTrx_string_pos;
1860 double QTrx_string_neg;
1862 double QTry_string_pos;
1864 double QTry_string_neg;
1867 double QTrn_string_pos;
1870 double QTrn_string_neg;
1872 std::array<double, 2> m_trans;
1875 const int niter_max = 10000;
1876 bool found_leading_baryon =
false;
1877 for (
int iiter = 0; iiter < niter_max; iiter++) {
1879 pdgid_frag_prior.clear();
1880 momentum_frag_prior.clear();
1882 std::vector<int> pdgid_frag;
1883 std::vector<FourVector> momentum_frag;
1885 ppos_string_new = mString * M_SQRT1_2;
1886 pneg_string_new = mString * M_SQRT1_2;
1888 QTrx_string_pos = 0.;
1889 QTrx_string_neg = 0.;
1890 QTrx_string_new = 0.;
1891 QTry_string_pos = 0.;
1892 QTry_string_neg = 0.;
1893 QTry_string_new = 0.;
1895 Pythia8::FlavContainer flav_string_pos =
1896 bstring > 0 ? Pythia8::FlavContainer(idq2)
1897 : Pythia8::FlavContainer(idq1);
1899 Pythia8::FlavContainer flav_string_neg =
1900 bstring > 0 ? Pythia8::FlavContainer(idq1)
1901 : Pythia8::FlavContainer(idq2);
1903 bool found_forward_baryon =
false;
1905 bool done_forward_end =
false;
1908 bool energy_used_up =
false;
1909 while (!found_forward_baryon && !energy_used_up) {
1920 separate_fragment_baryon && from_forward && !done_forward_end,
1921 evec_basis, ppos_string_new, pneg_string_new, QTrx_string_pos,
1922 QTrx_string_neg, QTry_string_pos, QTry_string_neg, flav_string_pos,
1923 flav_string_neg, pdgid_frag, momentum_frag);
1929 QTrx_string_new = QTrx_string_pos + QTrx_string_neg;
1930 QTry_string_new = QTry_string_pos + QTry_string_neg;
1934 idqIn[0] = bstring > 0 ? flav_string_neg.id : flav_string_pos.id;
1935 idqIn[1] = bstring > 0 ? flav_string_pos.id : flav_string_neg.id;
1936 for (
int i = 0; i < 2; i++) {
1939 QTrn_string_pos = std::sqrt(QTrx_string_pos * QTrx_string_pos +
1940 QTry_string_pos * QTry_string_pos);
1941 QTrn_string_neg = std::sqrt(QTrx_string_neg * QTrx_string_neg +
1942 QTry_string_neg * QTry_string_neg);
1947 m_trans[0] = std::sqrt(m_const[0] * m_const[0] +
1948 QTrn_string_neg * QTrn_string_neg);
1952 m_trans[1] = std::sqrt(m_const[1] * m_const[1] +
1953 QTrn_string_pos * QTrn_string_pos);
1958 m_trans[0] = std::sqrt(m_const[0] * m_const[0] +
1959 QTrn_string_pos * QTrn_string_pos);
1963 m_trans[1] = std::sqrt(m_const[1] * m_const[1] +
1964 QTrn_string_neg * QTrn_string_neg);
1966 done_forward_end = done_forward_end || from_forward;
1967 found_forward_baryon =
1968 found_forward_baryon ||
1973 energy_used_up =
true;
1977 n_frag_prior += n_frag;
1978 for (
int i_frag = 0; i_frag < n_frag; i_frag++) {
1979 pdgid_frag_prior.push_back(pdgid_frag[i_frag]);
1980 momentum_frag_prior.push_back(momentum_frag[i_frag]);
1988 double mTsqr_string = 2. * ppos_string_new * pneg_string_new;
1989 mTrn_string_new = std::sqrt(mTsqr_string);
1990 QTrn_string_new = std::sqrt(QTrx_string_new * QTrx_string_new +
1991 QTry_string_new * QTry_string_new);
1992 if (mTrn_string_new < QTrn_string_new) {
1995 found_leading_baryon =
false;
1999 std::sqrt(mTsqr_string - QTrn_string_new * QTrn_string_new);
2003 if (mass_string_new > m_const[0] + m_const[1]) {
2004 do_string_fragmentation =
true;
2005 found_leading_baryon =
true;
2006 QTrx_add_pos = QTrx_string_pos;
2007 QTry_add_pos = QTry_string_pos;
2008 QTrx_add_neg = QTrx_string_neg;
2009 QTry_add_neg = QTry_string_neg;
2011 found_leading_baryon =
false;
2014 }
else if (n_frag == 2) {
2017 do_string_fragmentation =
false;
2018 found_leading_baryon =
true;
2022 if (found_leading_baryon) {
2026 if (found_leading_baryon) {
2029 for (
int i_frag = 0; i_frag < n_frag_prior; i_frag++) {
2030 logg[
LPythia].debug(
"appending the the fragmented hadron ",
2031 pdgid_frag_prior[i_frag],
2032 " to the intermediate particle list.");
2035 momentum_frag_prior[i_frag],
2036 intermediate_particles);
2038 logg[
LPythia].error(
"PDG ID ", pdgid_frag_prior[i_frag],
2039 " should exist in ParticleType.");
2040 throw std::runtime_error(
"string fragmentation failed.");
2042 number_of_fragments++;
2050 if (do_string_fragmentation) {
2051 mTrn_string_new = std::sqrt(2. * ppos_string_new * pneg_string_new);
2053 std::array<double, 2> ppos_parton;
2055 std::array<double, 2> pneg_parton;
2063 const double pb_const =
2064 (mTrn_string_new * mTrn_string_new + m_trans[0] * m_trans[0] -
2065 m_trans[1] * m_trans[1]) /
2066 (4. * pneg_string_new);
2067 const double pc_const =
2068 0.5 * m_trans[0] * m_trans[0] * ppos_string_new / pneg_string_new;
2069 ppos_parton[0] = pb_const + (bstring > 0 ? -1. : 1.) *
2070 std::sqrt(pb_const * pb_const - pc_const);
2071 ppos_parton[1] = ppos_string_new - ppos_parton[0];
2075 for (
int i = 0; i < 2; i++) {
2076 pneg_parton[i] = 0.5 * m_trans[i] * m_trans[i] / ppos_parton[i];
2079 const int status = 1;
2080 int color, anticolor;
2083 Pythia8::Vec4 pquark;
2103 bstring > 0 ? evec_basis[1] * (QTrx_string_neg - QTrx_add_neg) +
2104 evec_basis[2] * (QTry_string_neg - QTry_add_neg)
2105 : evec_basis[1] * (QTrx_string_pos - QTrx_add_pos) +
2106 evec_basis[2] * (QTry_string_pos - QTry_add_pos);
2108 evec_basis[0] * (ppos_parton[0] - pneg_parton[0]) * M_SQRT1_2 +
2110 const double E_quark =
2111 std::sqrt(m_const[0] * m_const[0] + three_mom.
sqr());
2112 pquark =
set_Vec4(E_quark, three_mom);
2114 pythia_hadron_->event.append(idqIn[0], status, color, anticolor, pquark,
2135 bstring > 0 ? evec_basis[1] * (QTrx_string_pos - QTrx_add_pos) +
2136 evec_basis[2] * (QTry_string_pos - QTry_add_pos)
2137 : evec_basis[1] * (QTrx_string_neg - QTrx_add_neg) +
2138 evec_basis[2] * (QTry_string_neg - QTry_add_neg);
2140 evec_basis[0] * (ppos_parton[1] - pneg_parton[1]) * M_SQRT1_2 +
2142 const double E_antiq =
2143 std::sqrt(m_const[1] * m_const[1] + three_mom.
sqr());
2144 pquark =
set_Vec4(E_antiq, three_mom);
2146 pythia_hadron_->event.append(idqIn[1], status, color, anticolor, pquark,
2150 do_string_fragmentation =
true;
2152 ppos_string_new = mString * M_SQRT1_2;
2153 pneg_string_new = mString * M_SQRT1_2;
2154 QTrx_string_new = 0.;
2155 QTry_string_new = 0.;
2156 QTrn_string_new = 0.;
2157 mTrn_string_new = mString;
2158 mass_string_new = mString;
2163 double sign_direction = 1.;
2164 if (bstring == -3) {
2168 sign_direction = -1;
2172 const double pCMquark =
pCM(mString, m_const[0], m_const[1]);
2173 const double E1 = std::sqrt(m_const[0] * m_const[0] + pCMquark * pCMquark);
2174 const double E2 = std::sqrt(m_const[1] * m_const[1] + pCMquark * pCMquark);
2176 ThreeVector direction = sign_direction * evecLong;
2179 const int status1 = 1, color1 = 1, anticolor1 = 0;
2180 Pythia8::Vec4 pquark =
set_Vec4(E1, -direction * pCMquark);
2182 pythia_hadron_->event.append(idqIn[0], status1, color1, anticolor1, pquark,
2185 const int status2 = 1, color2 = 0, anticolor2 = 1;
2186 pquark =
set_Vec4(E2, direction * pCMquark);
2188 pythia_hadron_->event.append(idqIn[1], status2, color2, anticolor2, pquark,
2192 if (do_string_fragmentation) {
2193 logg[
LPythia].debug(
"fragmenting a string with ", idqIn[0],
", ", idqIn[1]);
2199 if (!successful_hadronization) {
2206 pythia_hadron_->event, evec_basis, ppos_string_new, pneg_string_new,
2207 QTrx_string_new, QTry_string_new, QTrx_add_pos, QTry_add_pos,
2208 QTrx_add_neg, QTry_add_neg);
2209 if (!successful_kinematics) {
2213 for (
int ipyth = 0; ipyth <
pythia_hadron_->event.size(); ipyth++) {
2224 logg[
LPythia].debug(
"appending the fragmented hadron ", pythia_id,
2225 " to the intermediate particle list.");
2230 " does not exist in ParticleType - start over.");
2231 intermediate_particles.clear();
2235 number_of_fragments++;
2238 return number_of_fragments;
2242 bool from_forward,
bool separate_fragment_baryon,
2243 std::array<ThreeVector, 3> &evec_basis,
double &ppos_string,
2244 double &pneg_string,
double &QTrx_string_pos,
double &QTrx_string_neg,
2245 double &QTry_string_pos,
double &QTry_string_neg,
2246 Pythia8::FlavContainer &flav_string_pos,
2247 Pythia8::FlavContainer &flav_string_neg, std::vector<int> &pdgid_frag,
2248 std::vector<FourVector> &momentum_frag) {
2251 const int n_try = 10;
2253 momentum_frag.clear();
2255 if (ppos_string < 0. || pneg_string < 0.) {
2256 throw std::runtime_error(
"string has a negative lightcone momentum.");
2258 double mTsqr_string = 2. * ppos_string * pneg_string;
2260 double mTrn_string = std::sqrt(mTsqr_string);
2262 double QTrx_string_tot = QTrx_string_pos + QTrx_string_neg;
2263 double QTry_string_tot = QTry_string_pos + QTry_string_neg;
2264 double QTsqr_string_tot = std::fabs(QTrx_string_tot * QTrx_string_tot) +
2265 std::fabs(QTry_string_tot * QTry_string_tot);
2266 double QTrn_string_tot = std::sqrt(QTsqr_string_tot);
2267 if (mTrn_string < QTrn_string_tot) {
2271 double mass_string = std::sqrt(mTsqr_string - QTsqr_string_tot);
2272 logg[
LPythia].debug(
" Fragment off one hadron from a string ( ",
2273 flav_string_pos.id,
" , ", flav_string_neg.id,
2274 " ) with mass ", mass_string,
" GeV.");
2277 const double sigma_qt_frag =
pythia_hadron_->parm(
"StringPT:sigma");
2278 const double stop_string_mass =
2280 const double stop_string_smear =
2284 const double prob_enhance_qt =
2286 double fac_enhance_qt;
2290 fac_enhance_qt = 1.;
2304 logg[
LPythia].debug(
" Transverse momentum (", QTrx_new,
", ", QTry_new,
2305 ") GeV selected for the new qqbar pair.");
2314 double QTrx_had_1st =
2315 from_forward ? QTrx_string_pos + QTrx_new : QTrx_string_neg + QTrx_new;
2316 double QTry_had_1st =
2317 from_forward ? QTry_string_pos + QTry_new : QTry_string_neg + QTry_new;
2318 double QTrn_had_1st =
2319 std::sqrt(QTrx_had_1st * QTrx_had_1st + QTry_had_1st * QTry_had_1st);
2322 int pdgid_had_1st = 0;
2324 double mass_had_1st = 0.;
2327 Pythia8::FlavContainer flav_old =
2328 from_forward ? flav_string_pos : flav_string_neg;
2333 Pythia8::FlavContainer flav_new = Pythia8::FlavContainer(0);
2337 for (
int i_try = 0; i_try < n_try; i_try++) {
2342 if (pdgid_had_1st != 0) {
2345 logg[
LPythia].debug(
" number of tries of flavor selection : ",
2346 i_try + 1,
" in StringProcess::fragment_off_hadron.");
2350 if (pdgid_had_1st == 0) {
2354 " selected for the string end with ", flav_old.id);
2356 " selected for the (first) fragmented hadron.");
2357 bool had_1st_baryon =
pythia_hadron_->particleData.isBaryon(pdgid_had_1st);
2359 double mTrn_had_1st =
2360 std::sqrt(mass_had_1st * mass_had_1st + QTrn_had_1st * QTrn_had_1st);
2361 logg[
LPythia].debug(
" Transverse momentum (", QTrx_had_1st,
", ",
2363 ") GeV selected for the (first) fragmented hadron.");
2368 const double mass_min_to_continue =
2369 (stop_string_mass +
pythia_hadron_->particleData.m0(flav_new.id) +
2375 bool string_into_final_two = mass_string < mass_min_to_continue;
2376 if (string_into_final_two) {
2377 logg[
LPythia].debug(
" The string mass is below the mass threshold ",
2378 mass_min_to_continue,
2379 " GeV : finishing with two hadrons.");
2383 double ppos_had_1st = 0.;
2384 double pneg_had_1st = 0.;
2388 bool from_diquark_end =
2389 from_forward ?
pythia_hadron_->particleData.isDiquark(flav_string_pos.id)
2392 bool has_diquark_pos =
2396 if (string_into_final_two) {
2400 int pdgid_had_2nd = 0.;
2402 double mass_had_2nd = 0.;
2405 Pythia8::FlavContainer flav_new2 = Pythia8::FlavContainer(0);
2406 flav_new2.anti(flav_new);
2409 if (
pythia_hadron_->particleData.isDiquark(flav_string_neg.id) &&
2410 pythia_hadron_->particleData.isDiquark(flav_new2.id) && from_forward) {
2413 if (
pythia_hadron_->particleData.isDiquark(flav_string_pos.id) &&
2414 pythia_hadron_->particleData.isDiquark(flav_new2.id) && !from_forward) {
2417 for (
int i_try = 0; i_try < n_try; i_try++) {
2422 if (pdgid_had_2nd != 0) {
2428 if (pdgid_had_2nd == 0) {
2432 " selected for the (second) fragmented hadron.");
2433 bool had_2nd_baryon =
pythia_hadron_->particleData.isBaryon(pdgid_had_2nd);
2441 double QTrx_had_2nd =
2442 from_forward ? QTrx_string_neg - QTrx_new : QTrx_string_pos - QTrx_new;
2443 double QTry_had_2nd =
2444 from_forward ? QTry_string_neg - QTry_new : QTry_string_pos - QTry_new;
2445 double QTrn_had_2nd =
2446 std::sqrt(QTrx_had_2nd * QTrx_had_2nd + QTry_had_2nd * QTry_had_2nd);
2447 double mTrn_had_2nd =
2448 std::sqrt(mass_had_2nd * mass_had_2nd + QTrn_had_2nd * QTrn_had_2nd);
2449 logg[
LPythia].debug(
" Transverse momentum (", QTrx_had_2nd,
", ",
2451 ") GeV selected for the (second) fragmented hadron.");
2453 double ppos_had_2nd = 0.;
2454 double pneg_had_2nd = 0.;
2460 bool found_kinematics =
2463 separate_fragment_baryon && has_diquark_pos && had_1st_baryon,
2464 ppos_string, pneg_string, mTrn_had_1st, mTrn_had_2nd,
2465 ppos_had_1st, ppos_had_2nd, pneg_had_1st, pneg_had_2nd)
2467 separate_fragment_baryon && has_diquark_pos && had_2nd_baryon,
2468 ppos_string, pneg_string, mTrn_had_2nd, mTrn_had_1st,
2469 ppos_had_2nd, ppos_had_1st, pneg_had_2nd, pneg_had_1st);
2470 if (!found_kinematics) {
2477 QTrx_string_pos = 0.;
2478 QTry_string_pos = 0.;
2481 pdgid_frag.push_back(pdgid_had_1st);
2483 (ppos_had_1st + pneg_had_1st) * M_SQRT1_2,
2484 evec_basis[0] * (ppos_had_1st - pneg_had_1st) * M_SQRT1_2 +
2485 evec_basis[1] * QTrx_had_1st + evec_basis[2] * QTry_had_1st);
2486 momentum_frag.push_back(mom_had_1st);
2489 pdgid_frag.push_back(pdgid_had_2nd);
2491 (ppos_had_2nd + pneg_had_2nd) * M_SQRT1_2,
2492 evec_basis[0] * (ppos_had_2nd - pneg_had_2nd) * M_SQRT1_2 +
2493 evec_basis[1] * QTrx_had_2nd + evec_basis[2] * QTry_had_2nd);
2494 momentum_frag.push_back(mom_had_2nd);
2503 double stringz_a_use, stringz_b_use;
2506 if (separate_fragment_baryon && from_diquark_end && had_1st_baryon) {
2516 double xfrac =
sample_zLund(stringz_a_use, stringz_b_use, mTrn_had_1st);
2520 ppos_had_1st = xfrac * ppos_string;
2521 pneg_had_1st = 0.5 * mTrn_had_1st * mTrn_had_1st / ppos_had_1st;
2522 if (pneg_had_1st > pneg_string) {
2528 pneg_had_1st = xfrac * pneg_string;
2529 ppos_had_1st = 0.5 * mTrn_had_1st * mTrn_had_1st / pneg_had_1st;
2530 if (ppos_had_1st > ppos_string) {
2536 pdgid_frag.push_back(pdgid_had_1st);
2538 (ppos_had_1st + pneg_had_1st) * M_SQRT1_2,
2539 evec_basis[0] * (ppos_had_1st - pneg_had_1st) * M_SQRT1_2 +
2540 evec_basis[1] * QTrx_had_1st + evec_basis[2] * QTry_had_1st);
2541 momentum_frag.push_back(mom_had_1st);
2544 ppos_string -= ppos_had_1st;
2545 pneg_string -= pneg_had_1st;
2555 flav_string_pos.anti(flav_new);
2556 QTrx_string_pos = -QTrx_new;
2557 QTry_string_pos = -QTry_new;
2561 flav_string_neg.anti(flav_new);
2562 QTrx_string_neg = -QTrx_new;
2563 QTry_string_neg = -QTry_new;
2573 const int baryon_number =
2577 int pdgid_hadron = 0;
2580 Pythia8::FlavContainer flav1 = Pythia8::FlavContainer(idq1);
2581 Pythia8::FlavContainer flav2 = Pythia8::FlavContainer(idq2);
2582 const int n_try = 10;
2583 for (
int i_try = 0; i_try < n_try; i_try++) {
2585 if (pdgid_hadron != 0) {
2586 return pdgid_hadron;
2594 std::array<int, 5> frag_net_q;
2597 for (
int iq = 0; iq < 5; iq++) {
2599 pythia_hadron_->particleData.nQuarksInCode(std::abs(idq1), iq + 1);
2601 pythia_hadron_->particleData.nQuarksInCode(std::abs(idq2), iq + 1);
2602 nq1 = idq1 > 0 ? nq1 : -nq1;
2603 nq2 = idq2 > 0 ? nq2 : -nq2;
2604 frag_net_q[iq] = nq1 + nq2;
2606 const int frag_iso3 = frag_net_q[1] - frag_net_q[0];
2607 const int frag_strange = -frag_net_q[2];
2608 const int frag_charm = frag_net_q[3];
2609 const int frag_bottom = -frag_net_q[4];
2610 logg[
LPythia].debug(
" conserved charges : iso3 = ", frag_iso3,
2611 ", strangeness = ", frag_strange,
2612 ", charmness = ", frag_charm,
2613 ", bottomness = ", frag_bottom);
2615 std::vector<int> pdgid_possible;
2616 std::vector<double> weight_possible;
2617 std::vector<double> weight_summed;
2622 if (!ptype.is_hadron()) {
2625 const int pdgid = ptype.pdgcode().get_decimal();
2627 (baryon_number == 3 * ptype.pdgcode().baryon_number()) &&
2628 (frag_iso3 == ptype.pdgcode().isospin3()) &&
2629 (frag_strange == ptype.pdgcode().strangeness()) &&
2630 (frag_charm == ptype.pdgcode().charmness()) &&
2631 (frag_bottom == ptype.pdgcode().bottomness())) {
2632 const int spin_degeneracy = ptype.pdgcode().spin_degeneracy();
2633 const double mass_pole = ptype.mass();
2634 const double weight =
static_cast<double>(spin_degeneracy) / mass_pole;
2635 pdgid_possible.push_back(pdgid);
2636 weight_possible.push_back(weight);
2638 logg[
LPythia].debug(
" PDG id ", pdgid,
" is possible with weight ",
2642 const int n_possible = pdgid_possible.size();
2643 weight_summed.push_back(0.);
2644 for (
int i = 0; i < n_possible; i++) {
2645 weight_summed.push_back(weight_summed[i] + weight_possible[i]);
2651 for (
int i = 0; i < n_possible; i++) {
2652 if ((uspc >= weight_summed[i]) && (uspc < weight_summed[i + 1])) {
2653 return pdgid_possible[i];
2670 bool end1_is_quark = idq1 > 0 &&
pythia_hadron_->particleData.isQuark(idq1);
2671 bool end1_is_antidiq =
2674 bool end2_is_antiq = idq2 < 0 &&
pythia_hadron_->particleData.isQuark(idq2);
2675 bool end2_is_diquark =
2679 if (end1_is_quark) {
2680 if (end2_is_antiq) {
2683 }
else if (end2_is_diquark) {
2689 }
else if (end1_is_antidiq) {
2690 if (end2_is_antiq) {
2703 std::array<int, 5> net_qnumber;
2704 for (
int iflav = 0; iflav < 5; iflav++) {
2705 net_qnumber[iflav] = 0;
2708 pythia_hadron_->particleData.nQuarksInCode(std::abs(idq1), iflav + 1);
2711 qnumber1 = -qnumber1;
2713 net_qnumber[iflav] += qnumber1;
2716 pythia_hadron_->particleData.nQuarksInCode(std::abs(idq2), iflav + 1);
2719 qnumber2 = -qnumber2;
2721 net_qnumber[iflav] += qnumber2;
2725 std::vector<int> pdgid_possible;
2727 std::vector<double> mass_diff;
2729 if (!ptype.is_hadron() || ptype.is_stable() ||
2730 ptype.pdgcode().baryon_number() != baryon) {
2734 const int pdgid = ptype.pdgcode().get_decimal();
2735 const double mass_min = ptype.min_mass_spectral();
2736 if (mass < mass_min) {
2741 if (ptype.pdgcode().isospin3() != net_qnumber[1] - net_qnumber[0]) {
2745 if (ptype.pdgcode().strangeness() != -net_qnumber[2]) {
2749 if (ptype.pdgcode().charmness() != net_qnumber[3]) {
2753 if (ptype.pdgcode().bottomness() != -net_qnumber[4]) {
2758 const double mass_pole = ptype.mass();
2760 pdgid_possible.push_back(pdgid);
2761 mass_diff.push_back(mass - mass_pole);
2764 const int n_res = pdgid_possible.size();
2770 int ires_closest = 0;
2771 double mass_diff_min = std::fabs(mass_diff[0]);
2774 for (
int ires = 1; ires < n_res; ires++) {
2775 if (std::fabs(mass_diff[ires]) < mass_diff_min) {
2776 ires_closest = ires;
2777 mass_diff_min = mass_diff[ires];
2780 logg[
LPythia].debug(
"Quark constituents ", idq1,
" and ", idq2,
" with mass ",
2781 mass,
" (GeV) turned into a resonance ",
2782 pdgid_possible[ires_closest]);
2783 return pdgid_possible[ires_closest];
2787 bool separate_fragment_hadron,
double ppos_string,
double pneg_string,
2788 double mTrn_had_forward,
double mTrn_had_backward,
double &ppos_had_forward,
2789 double &ppos_had_backward,
double &pneg_had_forward,
2790 double &pneg_had_backward) {
2791 const double mTsqr_string = 2. * ppos_string * pneg_string;
2792 if (mTsqr_string < 0.) {
2795 const double mTrn_string = std::sqrt(mTsqr_string);
2796 if (mTrn_string < mTrn_had_forward + mTrn_had_backward) {
2801 const double mTsqr_had_forward = mTrn_had_forward * mTrn_had_forward;
2803 const double mTsqr_had_backward = mTrn_had_backward * mTrn_had_backward;
2817 const double xm_diff =
2818 (mTsqr_had_forward - mTsqr_had_backward) / mTsqr_string;
2819 const double xe_pos = 0.5 * (1. + xm_diff);
2820 const double xe_neg = 0.5 * (1. - xm_diff);
2823 const double lambda_sqr =
2824 pow_int(mTsqr_string - mTsqr_had_forward - mTsqr_had_backward, 2) -
2825 4. * mTsqr_had_forward * mTsqr_had_backward;
2826 if (lambda_sqr <= 0.) {
2829 const double lambda = std::sqrt(lambda_sqr);
2830 const double b_lund =
2835 const double prob_reverse =
2836 std::exp(-b_lund * lambda) / (1. + std::exp(-b_lund * lambda));
2837 double xpz_pos = 0.5 * lambda / mTsqr_string;
2842 ppos_had_forward = (xe_pos + xpz_pos) * ppos_string;
2843 ppos_had_backward = (xe_neg - xpz_pos) * ppos_string;
2845 pneg_had_forward = 0.5 * mTsqr_had_forward / ppos_had_forward;
2846 pneg_had_backward = 0.5 * mTsqr_had_backward / ppos_had_backward;
2854 bool xfrac_accepted =
false;
2862 while (!xfrac_accepted) {
2863 const double fac_env = b * mTrn * mTrn;
2867 const double xfrac_inv = 1. - std::log(u_aux) / fac_env;
2868 assert(xfrac_inv >= 1.);
2871 const double xf_ratio = std::pow(1. - 1. / xfrac_inv, a) / xfrac_inv;
2876 xfrac = 1. / xfrac_inv;
2877 xfrac_accepted =
true;
2884 Pythia8::Event &event_fragments, std::array<ThreeVector, 3> &evec_basis,
2885 double ppos_string,
double pneg_string,
double QTrx_string,
2886 double QTry_string,
double QTrx_add_pos,
double QTry_add_pos,
2887 double QTrx_add_neg,
double QTry_add_neg) {
2888 logg[
LPythia].debug(
"Correcting the kinematics of fragmented hadrons...");
2890 if (ppos_string < 0. || pneg_string < 0.) {
2892 " wrong lightcone momenta of string : ppos_string (GeV) = ",
2893 ppos_string,
" pneg_string (GeV) = ", pneg_string);
2897 const double yrapid_string = 0.5 * std::log(ppos_string / pneg_string);
2898 logg[
LOutput].debug(
"Momentum-space rapidity of the string should be ",
2902 const double mTrn_string = std::sqrt(2. * ppos_string * pneg_string);
2903 logg[
LOutput].debug(
"Transvere mass (GeV) of the string should be ",
2906 const double QTrn_string =
2907 std::sqrt(QTrx_string * QTrx_string + QTry_string * QTry_string);
2908 if (mTrn_string < QTrn_string) {
2910 " wrong transverse mass of string : mTrn_string (GeV) = ", mTrn_string,
2911 " QTrn_string (GeV) = ", QTrn_string);
2914 const double msqr_string =
2915 mTrn_string * mTrn_string - QTrn_string * QTrn_string;
2917 const double mass_string = std::sqrt(msqr_string);
2918 logg[
LOutput].debug(
"The string mass (GeV) should be ", mass_string);
2922 if (std::fabs(QTrx_add_pos) <
small_number * mass_string &&
2923 std::fabs(QTry_add_pos) <
small_number * mass_string &&
2924 std::fabs(QTrx_add_neg) <
small_number * mass_string &&
2925 std::fabs(QTry_add_neg) <
small_number * mass_string) {
2926 logg[
LOutput].debug(
" no need to add transverse momenta - skipping.");
2932 for (
int ipyth = 1; ipyth < event_fragments.size(); ipyth++) {
2933 if (!event_fragments[ipyth].isFinal()) {
2938 FourVector(event_fragments[ipyth].e(), event_fragments[ipyth].px(),
2939 event_fragments[ipyth].py(), event_fragments[ipyth].pz());
2940 ptot_string_ini += p_frag;
2942 const double E_string_ini = ptot_string_ini.
x0();
2943 const double pz_string_ini = ptot_string_ini.
threevec() * evec_basis[0];
2944 const double ppos_string_ini = (E_string_ini + pz_string_ini) * M_SQRT1_2;
2945 const double pneg_string_ini = (E_string_ini - pz_string_ini) * M_SQRT1_2;
2947 const double yrapid_string_ini =
2948 0.5 * std::log(ppos_string_ini / pneg_string_ini);
2954 int ip_backward = 0;
2955 double y_forward = 0.;
2956 double y_backward = 0.;
2957 ptot_string_ini =
FourVector(0., 0., 0., 0.);
2959 for (
int ipyth = 1; ipyth < event_fragments.size(); ipyth++) {
2960 if (!event_fragments[ipyth].isFinal()) {
2965 FourVector(event_fragments[ipyth].e(), event_fragments[ipyth].px(),
2966 event_fragments[ipyth].py(), event_fragments[ipyth].pz());
2967 ptot_string_ini += p_frag;
2969 const double E_frag = p_frag.
x0();
2970 const double pl_frag = p_frag.
threevec() * evec_basis[0];
2971 double y_current = 0.5 * std::log((E_frag + pl_frag) / (E_frag - pl_frag));
2972 if (y_current > y_forward) {
2974 y_forward = y_current;
2976 if (y_current < y_backward) {
2977 ip_backward = ipyth;
2978 y_backward = y_current;
2981 logg[
LOutput].debug(
" The most forward hadron is ip_forward = ", ip_forward,
2982 " with rapidity ", y_forward);
2983 logg[
LOutput].debug(
" The most backward hadron is ip_backward = ",
2984 ip_backward,
" with rapidity ", y_backward);
2986 const double px_string_ini = ptot_string_ini.
threevec() * evec_basis[1];
2987 const double py_string_ini = ptot_string_ini.
threevec() * evec_basis[2];
2991 bool correct_px = std::fabs(px_string_ini + QTrx_add_pos + QTrx_add_neg -
2995 " input transverse momenta in x-axis are not consistent.");
3000 bool correct_py = std::fabs(py_string_ini + QTry_add_pos + QTry_add_neg -
3004 " input transverse momenta in y-axis are not consistent.");
3008 Pythia8::Vec4 pvec_string_now =
3012 " Adding transverse momentum to the most forward hadron.");
3013 pvec_string_now -= event_fragments[ip_forward].p();
3014 const double mass_frag_pos = event_fragments[ip_forward].p().mCalc();
3017 event_fragments[ip_forward].e(), event_fragments[ip_forward].px(),
3018 event_fragments[ip_forward].py(), event_fragments[ip_forward].pz());
3021 QTrx_add_pos * evec_basis[1] +
3022 QTry_add_pos * evec_basis[2];
3024 double E_new_frag_pos =
3025 std::sqrt(mom_new_frag_pos.
sqr() + mass_frag_pos * mass_frag_pos);
3026 Pythia8::Vec4 pvec_new_frag_pos =
set_Vec4(E_new_frag_pos, mom_new_frag_pos);
3027 pvec_string_now += pvec_new_frag_pos;
3029 event_fragments[ip_forward].p(pvec_new_frag_pos);
3032 " Adding transverse momentum to the most backward hadron.");
3033 pvec_string_now -= event_fragments[ip_backward].p();
3034 const double mass_frag_neg = event_fragments[ip_backward].p().mCalc();
3037 event_fragments[ip_backward].e(), event_fragments[ip_backward].px(),
3038 event_fragments[ip_backward].py(), event_fragments[ip_backward].pz());
3041 QTrx_add_neg * evec_basis[1] +
3042 QTry_add_neg * evec_basis[2];
3044 double E_new_frag_neg =
3045 std::sqrt(mom_new_frag_neg.
sqr() + mass_frag_neg * mass_frag_neg);
3046 Pythia8::Vec4 pvec_new_frag_neg =
set_Vec4(E_new_frag_neg, mom_new_frag_neg);
3047 pvec_string_now += pvec_new_frag_neg;
3049 event_fragments[ip_backward].p(pvec_new_frag_neg);
3052 event_fragments[0].p(pvec_string_now);
3053 event_fragments[0].m(pvec_string_now.mCalc());
3056 double mTrn_frag_all = 0.;
3057 for (
int ipyth = 1; ipyth < event_fragments.size(); ipyth++) {
3058 if (!event_fragments[ipyth].isFinal()) {
3063 FourVector(event_fragments[ipyth].e(), event_fragments[ipyth].px(),
3064 event_fragments[ipyth].py(), event_fragments[ipyth].pz());
3065 ptot_string_ini += p_frag;
3067 const double E_frag = p_frag.
x0();
3068 const double pl_frag = p_frag.
threevec() * evec_basis[0];
3069 const double ppos_frag = (E_frag + pl_frag) * M_SQRT1_2;
3070 const double pneg_frag = (E_frag - pl_frag) * M_SQRT1_2;
3071 const double mTrn_frag = std::sqrt(2. * ppos_frag * pneg_frag);
3072 mTrn_frag_all += mTrn_frag;
3075 "Sum of transverse masses (GeV) of all fragmented hadrons : ",
3079 if (mTrn_string < mTrn_frag_all) {
3080 logg[
LOutput].debug(
" which is larger than mT of the actual string ",
3085 double mass_string_now = pvec_string_now.mCalc();
3086 double msqr_string_now = mass_string_now * mass_string_now;
3089 FourVector(pvec_string_now.e(), pvec_string_now.px(),
3090 pvec_string_now.py(), pvec_string_now.pz());
3091 double E_string_now = p_string_now.
x0();
3092 double pz_string_now = p_string_now.
threevec() * evec_basis[0];
3093 logg[
LOutput].debug(
"The string mass (GeV) at this point : ",
3095 double ppos_string_now = (E_string_now + pz_string_now) * M_SQRT1_2;
3096 double pneg_string_now = (E_string_now - pz_string_now) * M_SQRT1_2;
3098 double yrapid_string_now = 0.5 * std::log(ppos_string_now / pneg_string_now);
3099 logg[
LOutput].debug(
"The momentum-space rapidity of string at this point : ",
3102 "The momentum-space rapidities of hadrons will be changed.");
3103 const int niter_max = 10000;
3104 bool accepted =
false;
3105 double fac_all_yrapid = 1.;
3110 for (
int iiter = 0; iiter < niter_max; iiter++) {
3111 if (std::fabs(mass_string_now - mass_string) <
really_small * mass_string) {
3115 double E_deriv = 0.;
3116 double pz_deriv = 0.;
3120 for (
int ipyth = 1; ipyth < event_fragments.size(); ipyth++) {
3121 if (!event_fragments[ipyth].isFinal()) {
3126 FourVector(event_fragments[ipyth].e(), event_fragments[ipyth].px(),
3127 event_fragments[ipyth].py(), event_fragments[ipyth].pz());
3128 const double E_frag = p_frag.
x0();
3129 const double pl_frag = p_frag.
threevec() * evec_basis[0];
3130 const double ppos_frag = (E_frag + pl_frag) * M_SQRT1_2;
3131 const double pneg_frag = (E_frag - pl_frag) * M_SQRT1_2;
3132 const double mTrn_frag = std::sqrt(2. * ppos_frag * pneg_frag);
3133 const double y_frag = 0.5 * std::log(ppos_frag / pneg_frag);
3135 E_deriv += mTrn_frag * (y_frag - yrapid_string_now) * std::sinh(y_frag);
3136 pz_deriv += mTrn_frag * (y_frag - yrapid_string_now) * std::cosh(y_frag);
3138 double slope = 2. * (E_string_now * E_deriv - pz_string_now * pz_deriv);
3139 double fac_yrapid = 1. + std::tanh((msqr_string - msqr_string_now) / slope);
3140 fac_all_yrapid *= fac_yrapid;
3144 (1. - fac_yrapid) * yrapid_string_now);
3146 pvec_string_now = event_fragments[0].p();
3147 mass_string_now = pvec_string_now.mCalc();
3148 msqr_string_now = mass_string_now * mass_string_now;
3149 p_string_now =
FourVector(pvec_string_now.e(), pvec_string_now.px(),
3150 pvec_string_now.py(), pvec_string_now.pz());
3151 E_string_now = p_string_now.
x0();
3152 pz_string_now = p_string_now.
threevec() * evec_basis[0];
3153 ppos_string_now = (E_string_now + pz_string_now) * M_SQRT1_2;
3154 pneg_string_now = (E_string_now - pz_string_now) * M_SQRT1_2;
3155 yrapid_string_now = 0.5 * std::log(ppos_string_now / pneg_string_now);
3156 logg[
LOutput].debug(
" step ", iiter + 1,
" : fac_yrapid = ", fac_yrapid,
3157 " , string mass (GeV) = ", mass_string_now,
3158 " , string rapidity = ", yrapid_string_now);
3162 logg[
LOutput].debug(
" Too many iterations in rapidity rescaling.");
3166 "The overall factor multiplied to the rapidities of hadrons = ",
3168 logg[
LOutput].debug(
"The momentum-space rapidity of string at this point : ",
3170 const double y_diff = yrapid_string - yrapid_string_now;
3171 logg[
LOutput].debug(
"The hadrons will be boosted by rapidity ", y_diff,
3172 " for the longitudinal momentum conservation.");
3181 double suppression_factor) {
3196 ParticleList &list) {
3197 assert(list.size() >= 2);
3198 int end = list.size() - 1;
3201 i1 <= end && !list[i1].pdgcode().contains_enough_valence_quarks(nq1);
3205 i2 >= 0 && !list[i2].pdgcode().contains_enough_valence_quarks(nq2);
3208 std::pair<int, int> indices(i1, i2);
3213 ParticleList &outgoing_particles,
3215 double suppression_factor) {
3218 data.set_cross_section_scaling_factor(0.0);
3221 std::sort(outgoing_particles.begin(), outgoing_particles.end(),
3223 return i.momentum().velocity() * evecLong >
3224 j.momentum().velocity() * evecLong;
3227 switch (baryon_string) {
3241 throw std::runtime_error(
"string is neither mesonic nor baryonic");
3246 std::pair<int, int> i =
find_leading(nq1, nq2, outgoing_particles);
3247 std::pair<int, int> j =
find_leading(nq2, nq1, outgoing_particles);
3248 if (baryon_string == 0 && i.second - i.first < j.second - j.first) {
3251 suppression_factor);
3255 suppression_factor);
3275 throw std::runtime_error(
"StringProcess::pdg_map_for_pythia failed.");
The FourVector class holds relevant values in Minkowski spacetime with (+, −, −, −) metric signature.
FourVector lorentz_boost(const ThreeVector &v) const
Returns the FourVector boosted with velocity v.
ThreeVector threevec() const
ThreeVector velocity() const
Get the velocity (3-vector divided by zero component).
ParticleData contains the dynamic information of a certain particle.
PdgCode pdgcode() const
Get the pdgcode of the particle.
void set_4momentum(const FourVector &momentum_vector)
Set the particle's 4-momentum directly.
void set_cross_section_scaling_factor(const double &xsec_scal)
Set the particle's initial cross_section_scaling_factor.
void set_formation_time(const double &form_time)
Set the absolute formation time.
static const ParticleType & find(PdgCode pdgcode)
Returns the ParticleType object for the given pdgcode.
static const ParticleTypeList & list_all()
PdgCode stores a Particle Data Group Particle Numbering Scheme particle type number.
int baryon_number() const
int net_quark_number(const int quark) const
Returns the net number of quarks with given flavour number For public use, see strangeness(),...
std::array< int, 3 > quark_content() const
The return is always an array of three numbers, which are pdgcodes of quarks: 1 - d,...
int32_t get_decimal() const
int charge() const
The charge of the particle.
Pythia8::StringFlav pythia_stringflav_
An object for the flavor selection in string fragmentation in the case of separate fragmentation func...
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)
bool next_SDiff(bool is_AB_to_AX)
Single-diffractive process is based on single pomeron exchange described in Ingelman:1984ns .
pythia_map hard_map_
Map object to contain the different pythia objects.
static FourVector reorient(Pythia8::Particle &particle, std::array< ThreeVector, 3 > &evec_basis)
compute the four-momentum properly oriented in the lab frame.
Pythia8::SigmaTotal pythia_sigmatot_
An object to compute cross-sections.
double pow_fgluon_beta_
parameter for the gluon distribution function
std::array< int, 2 > NpartString_
number of particles fragmented from strings
Pythia8::Event event_intermediate_
event record for intermediate partonic state in the hard string routine
std::array< PdgCode, 2 > PDGcodes_
PdgCodes of incoming particles.
double time_formation_const_
constant proper time in the case of constant formation time [fm]
double PNegB_
backward lightcone momentum p^{-} of incoming particle B in CM-frame [GeV]
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.
double pow_fquark_beta_
parameter for the quark distribution function
bool next_NDiffSoft()
Soft Non-diffractive process is modelled in accordance with dual-topological approach Capella:1978ig ...
bool next_DDiff()
Double-diffractive process ( A + B -> X + X ) is similar to the single-diffractive process,...
static int pdg_map_for_pythia(PdgCode &pdg)
Take pdg code and map onto particle specie which can be handled by PYTHIA.
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...
FourVector ucomAB_
velocity four vector of the center of mass in the lab frame
ThreeVector vcomAB_
velocity three vector of the center of mass in the lab frame
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.
void compute_incoming_lightcone_momenta()
compute the lightcone momenta of incoming particles where the longitudinal direction is set to be sam...
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 exploiting PYTHIA 8....
double popcorn_rate_
popcorn rate
double pmin_gluon_lightcone_
the minimum lightcone momentum scale carried by a gluon [GeV]
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...
static std::pair< int, int > find_leading(int nq1, int nq2, ParticleList &list)
Find the leading string fragments.
double PPosA_
forward lightcone momentum p^{+} of incoming particle A in CM-frame [GeV]
double sqrtsAB_
sqrt of Mandelstam variable s of collision [GeV]
ParticleList final_state_
final state array which must be accessed after the collision
double PNegA_
backward lightcone momentum p^{-} of incoming particle A in CM-frame [GeV]
static double sample_zLund(double a, double b, double mTrn)
Sample lightcone momentum fraction according to the LUND fragmentation function.
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...
bool use_monash_tune_
Whether to use the monash tune Skands:2014pea for all string processes.
double soft_t_form_
factor to be multiplied to formation times in soft strings
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.
std::unique_ptr< Pythia8::Pythia > pythia_hadron_
PYTHIA object used in fragmentation.
double massA_
mass of incoming particle A [GeV]
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.
double PPosB_
forward lightcone momentum p^{+} of incoming particle B in CM-frame [GeV]
std::array< ThreeVector, 3 > evecBasisAB_
Orthonormal basis vectors in the center of mass frame, where the 0th one is parallel to momentum of i...
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...
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...
double string_sigma_T_
transverse momentum spread in string fragmentation
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
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.
static void convert_KaonLS(int &pythia_id)
convert Kaon-L or Kaon-S into K0 or Anti-K0
double additional_xsec_supp_
additional cross-section suppression factor to take coherence effect into account.
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.
double strange_supp_
strange quark suppression factor
static int diquark_from_quarks(int q1, int q2)
Construct diquark from two quarks.
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...
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.
double kappa_tension_string_
string tension [GeV/fm]
double pow_fquark_alpha_
parameter for the quark distribution function
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.
double stringz_b_leading_
parameter (StringZ:bLund) for the fragmentation function of leading baryon in soft non-diffractive st...
static bool append_intermediate_list(int pdgid, FourVector momentum, ParticleList &intermediate_particles)
append new particle from PYTHIA to a specific particle list
bool mass_dependent_formation_times_
Whether the formation time should depend on the mass of the fragment according to Andersson:1983ia e...
double stringz_b_produce_
parameter (StringZ:bLund) for the fragmentation function of other (produced) hadrons in soft non-diff...
bool next_BBbarAnn()
Baryon-antibaryon annihilation process Based on what UrQMD Bass:1998ca , Bleicher:1999xi does,...
int NpartFinal_
total number of final state particles
static Pythia8::Vec4 set_Vec4(double energy, const ThreeVector &mom)
Easy setter of Pythia Vec4 from SMASH.
double stringz_a_leading_
parameter (StringZ:aLund) for the fragmentation function of leading baryon in soft non-diffractive st...
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.
void init(const ParticleList &incoming, double tcoll)
initialization feed intial particles, time of collision and gamma factor of the center of mass.
double sigma_qperp_
Transverse momentum spread of the excited strings.
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...
int get_resonance_from_quark(int idq1, int idq2, double mass)
bool next_NDiffHard()
Hard Non-diffractive process is based on PYTHIA 8 with partonic showers and interactions.
bool separate_fragment_baryon_
Whether to use a separate fragmentation function for leading baryons.
std::array< FourVector, 2 > plab_
momenta of incoming particles in the lab frame [GeV]
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, bool use_monash_tune)
Constructor, initializes pythia.
std::array< FourVector, 2 > pcom_
momenta of incoming particles in the center of mass frame [GeV]
double time_collision_
time of collision in the computational frame [fm]
int get_hadrontype_from_quark(int idq1, int idq2)
Determines hadron type from valence quark constituents.
double diquark_supp_
diquark suppression factor
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...
double massB_
mass of incoming particle B [GeV]
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...
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 ...
double stringz_a_produce_
parameter (StringZ:aLund) for the fragmentation function of other (produced) hadrons in soft non-diff...
static void assign_scaling_factor(int nquark, ParticleData &data, double suppression_factor)
Assign a cross section scaling factor to the given particle.
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,...
static void quarks_from_diquark(int diquark, int &q1, int &q2, int °_spin)
find two quarks from a diquark.
The ThreeVector class represents a physical three-vector with the components .
Discrete distribution with weight given by probability vector.
std::array< einhard::Logger<>, std::tuple_size< LogArea::AreaTuple >::value > logg
An array that stores all pre-configured Logger objects.
T power(T n, T xMin, T xMax)
Draws a random number according to a power-law distribution ~ x^n.
T beta_a0(T xmin, T b)
Draws a random number from a beta-distribution with a = 0.
T beta(T a, T b)
Draws a random number from a beta-distribution, where probability density of is .
double normal(const T &mean, const T &sigma)
Returns a random number drawn from a normal distribution.
T uniform_int(T min, T max)
T pCM(const T sqrts, const T mass_a, const T mass_b) noexcept
T pCM_sqr(const T sqrts, const T mass_a, const T mass_b) noexcept
constexpr int maximum_rndm_seed_in_pythia
The maximum value of the random seed used in PYTHIA.
constexpr double small_number
Physical error tolerance.
constexpr T pow_int(const T base, unsigned const exponent)
Efficient template for calculating integer powers using squaring.
static constexpr int LOutput
constexpr double pion_mass
Pion mass in GeV.
constexpr double really_small
Numerical error tolerance.
constexpr double kaon_mass
Kaon mass in GeV.
static constexpr int LPythia