19 static constexpr
int LOutput = LogArea::Output::id;
22 double string_tension,
double time_formation,
double gluon_beta,
23 double gluon_pmin,
double quark_alpha,
double quark_beta,
24 double strange_supp,
double diquark_supp,
double sigma_perp,
25 double stringz_a_leading,
double stringz_b_leading,
double stringz_a,
26 double stringz_b,
double string_sigma_T,
double factor_t_form,
27 bool mass_dependent_formation_times,
double prob_proton_to_d_uu,
28 bool separate_fragment_baryon,
double popcorn_rate)
29 : pmin_gluon_lightcone_(gluon_pmin),
30 pow_fgluon_beta_(gluon_beta),
31 pow_fquark_alpha_(quark_alpha),
32 pow_fquark_beta_(quark_beta),
33 sigma_qperp_(sigma_perp),
34 stringz_a_leading_(stringz_a_leading),
35 stringz_b_leading_(stringz_b_leading),
36 stringz_a_produce_(stringz_a),
37 stringz_b_produce_(stringz_b),
38 strange_supp_(strange_supp),
39 diquark_supp_(diquark_supp),
40 popcorn_rate_(popcorn_rate),
41 string_sigma_T_(string_sigma_T),
42 kappa_tension_string_(string_tension),
43 additional_xsec_supp_(0.7),
44 time_formation_const_(time_formation),
45 soft_t_form_(factor_t_form),
47 mass_dependent_formation_times_(mass_dependent_formation_times),
48 prob_proton_to_d_uu_(prob_proton_to_d_uu),
49 separate_fragment_baryon_(separate_fragment_baryon) {
51 pythia_hadron_ = make_unique<Pythia8::Pythia>(PYTHIA_XML_DIR,
false);
55 popcorn_rate, stringz_a, stringz_b, string_sigma_T);
80 for (
int imu = 0; imu < 3; imu++) {
90 double popcorn_rate,
double stringz_a,
92 double string_sigma_T) {
94 pythia_in->readString(
"ParticleData:modeBreitWigner = 4");
97 pythia_in->readString(
"MultipartonInteractions:pTmin = 1.5");
98 pythia_in->readString(
"MultipartonInteractions:nSample = 10000");
100 pythia_in->readString(
"StringPT:sigma = " + std::to_string(string_sigma_T));
102 pythia_in->readString(
"StringFlav:probQQtoQ = " +
103 std::to_string(diquark_supp));
105 pythia_in->readString(
"StringFlav:probStoUD = " +
106 std::to_string(strange_supp));
107 pythia_in->readString(
"StringFlav:popcornRate = " +
108 std::to_string(popcorn_rate));
110 pythia_in->readString(
"StringZ:aLund = " + std::to_string(stringz_a));
111 pythia_in->readString(
"StringZ:bLund = " + std::to_string(stringz_b));
114 pythia_in->readString(
"PDF:pSet = 13");
115 pythia_in->readString(
"PDF:pSetB = 13");
116 pythia_in->readString(
"PDF:piSet = 1");
117 pythia_in->readString(
"PDF:piSetB = 1");
118 pythia_in->readString(
"Beams:idA = 2212");
119 pythia_in->readString(
"Beams:idB = 2212");
120 pythia_in->readString(
"Beams:eCM = 10.");
123 pythia_in->readString(
"Random:setSeed = on");
125 pythia_in->readString(
"Print:quiet = on");
127 pythia_in->readString(
"HadronLevel:Decay = off");
130 int pdgid = ptype.pdgcode().get_decimal();
131 double mass_pole = ptype.mass();
132 double width_pole = ptype.width_at_pole();
134 if (pythia_in->particleData.isParticle(pdgid)) {
136 pythia_in->particleData.m0(pdgid, mass_pole);
137 pythia_in->particleData.mWidth(pdgid, width_pole);
138 }
else if (pdgid == 310 || pdgid == 130) {
140 pythia_in->particleData.m0(pdgid,
kaon_mass);
141 pythia_in->particleData.mWidth(pdgid, 0.);
146 pythia_in->readString(
"Check:epTolErr = 1e-6");
147 pythia_in->readString(
"Check:epTolWarn = 1e-8");
159 bstring += data.pdgcode().baryon_number();
172 for (
int i = 0; i < nfrag; i++) {
173 ThreeVector velocity = intermediate_particles[i].momentum().velocity();
174 double gamma = 1. / intermediate_particles[i].inverse_gamma();
177 intermediate_particles[i].momentum().
lorentz_boost(-vstring);
178 intermediate_particles[i].set_4momentum(momentum);
182 double tau_prod = M_SQRT2 * intermediate_particles[i].effective_mass() /
184 double t_prod = tau_prod * gamma;
188 fragment_position = fragment_position.
lorentz_boost(-vstring);
190 intermediate_particles[i].set_slow_formation_times(
195 double gamma_factor = 1.0 / std::sqrt(1 - (v_calc).sqr());
196 intermediate_particles[i].set_slow_formation_times(
210 massA_ = incoming[0].effective_mass();
211 massB_ = incoming[1].effective_mass();
213 plab_[0] = incoming[0].momentum();
214 plab_[1] = incoming[1].momentum();
247 double QTrn, QTrx, QTry;
248 double pabscomHX_sqr, massX;
257 if (mstrMin > mstrMax) {
263 QTrn = std::sqrt(QTrx * QTrx + QTry * QTry);
270 const bool foundPabsX = pabscomHX_sqr > QTrn * QTrn;
275 double sign_direction = is_AB_to_AX ? 1. : -1.;
279 (
evecBasisAB_[0] * std::sqrt(pabscomHX_sqr - QTrn * QTrn) +
281 const FourVector pstrHcom(std::sqrt(pabscomHX_sqr + massH * massH),
283 const FourVector pstrXcom(std::sqrt(pabscomHX_sqr + massX * massX),
291 is_AB_to_AX ?
pcom_[1].threevec() :
pcom_[0].threevec();
296 ParticleList new_intermediate_particles;
298 new_intermediate_particles);
319 const std::array<std::array<int, 2>, 2> &quarks,
320 const std::array<FourVector, 2> &pstr_com, std::array<double, 2> &m_str,
321 std::array<ThreeVector, 2> &evec_str) {
322 std::array<bool, 2> found_mass;
323 for (
int i = 0; i < 2; i++) {
324 found_mass[i] =
false;
326 m_str[i] = pstr_com[i].sqr();
327 m_str[i] = (m_str[i] > 0.) ? std::sqrt(m_str[i]) : 0.;
328 const double threshold =
pythia_hadron_->particleData.m0(quarks[i][0]) +
331 if (m_str[i] > threshold) {
332 found_mass[i] =
true;
352 return found_mass[0] && found_mass[1];
356 const std::array<std::array<int, 2>, 2> &quarks,
357 const std::array<FourVector, 2> &pstr_com,
358 const std::array<double, 2> &m_str,
359 const std::array<ThreeVector, 2> &evec_str,
bool flip_string_ends,
360 bool separate_fragment_baryon) {
361 const std::array<FourVector, 2> ustr_com = {pstr_com[0] / m_str[0],
362 pstr_com[1] / m_str[1]};
363 for (
int i = 0; i < 2; i++) {
364 ParticleList new_intermediate_particles;
369 int nfrag =
fragment_string(quarks[i][0], quarks[i][1], m_str[i], evec,
370 flip_string_ends, separate_fragment_baryon,
371 new_intermediate_particles);
394 std::array<std::array<int, 2>, 2> quarks;
395 std::array<FourVector, 2> pstr_com;
396 std::array<double, 2> m_str;
397 std::array<ThreeVector, 2> evec_str;
407 const double xfracA =
409 const double xfracB =
414 const double QTrn = std::sqrt(QTrx * QTrx + QTry * QTry);
416 const double QPos = -QTrn * QTrn / (2. * xfracB *
PNegB_);
417 const double QNeg = QTrn * QTrn / (2. * xfracA *
PPosA_);
431 const bool found_masses =
436 const bool flip_string_ends =
true;
438 quarks, pstr_com, m_str, evec_str, flip_string_ends,
false);
449 std::array<std::array<int, 2>, 2> quarks;
450 std::array<FourVector, 2> pstr_com;
451 std::array<double, 2> m_str;
452 std::array<ThreeVector, 2> evec_str;
455 int idqA1, idqA2, idqB1, idqB2;
459 const int bar_a =
PDGcodes_[0].baryon_number(),
462 (bar_a == 0 && bar_b == 1) ||
463 (bar_a == 0 && bar_b == 0)) {
464 quarks[0][0] = idqB1;
465 quarks[0][1] = idqA2;
466 quarks[1][0] = idqA1;
467 quarks[1][1] = idqB2;
468 }
else if (((bar_a == 0) && (bar_b == -1)) ||
471 quarks[0][0] = idqA1;
472 quarks[0][1] = idqB2;
473 quarks[1][0] = idqB1;
474 quarks[1][1] = idqA2;
476 std::stringstream ss;
477 ss <<
" StringProcess::next_NDiff : baryonA = " << bar_a
478 <<
", baryonB = " << bar_b;
479 throw std::runtime_error(ss.str());
487 const double QTrn = std::sqrt(QTrx * QTrx + QTry * QTry);
489 const double QPos = -QTrn * QTrn / (2. * xfracB *
PNegB_);
490 const double QNeg = QTrn * QTrn / (2. * xfracA *
PPosA_);
491 const double dPPos = -xfracA *
PPosA_ - QPos;
492 const double dPNeg = xfracB *
PNegB_ - QNeg;
499 m_str[0] = pstr_com[0].sqr();
507 const bool found_masses =
512 const bool flip_string_ends =
false;
527 std::array<int, 2> pdg_for_pythia;
528 std::array<std::array<int, 5>, 2> excess_quark;
529 std::array<std::array<int, 5>, 2> excess_antiq;
530 for (
int i = 0; i < 2; i++) {
531 for (
int j = 0; j < 5; j++) {
532 excess_quark[i][j] = 0;
533 excess_antiq[i][j] = 0;
539 " is mapped onto ", pdg_for_pythia[i]);
541 PdgCode pdgcode_for_pythia(std::to_string(pdg_for_pythia[i]));
546 logg[
LPythia].debug(
" excess_quark[", i,
"] = (", excess_quark[i][0],
547 ", ", excess_quark[i][1],
", ", excess_quark[i][2],
548 ", ", excess_quark[i][3],
", ", excess_quark[i][4],
550 logg[
LPythia].debug(
" excess_antiq[", i,
"] = (", excess_antiq[i][0],
551 ", ", excess_antiq[i][1],
", ", excess_antiq[i][2],
552 ", ", excess_antiq[i][3],
", ", excess_antiq[i][4],
556 std::pair<int, int> idAB{pdg_for_pythia[0], pdg_for_pythia[1]};
561 hard_map_[idAB] = make_unique<Pythia8::Pythia>(PYTHIA_XML_DIR,
false);
562 hard_map_[idAB]->readString(
"SoftQCD:nonDiffractive = on");
563 hard_map_[idAB]->readString(
"MultipartonInteractions:pTmin = 1.5");
564 hard_map_[idAB]->readString(
"HadronLevel:all = off");
570 hard_map_[idAB]->settings.flag(
"Beams:allowVariableEnergy",
true);
572 hard_map_[idAB]->settings.mode(
"Beams:idA", idAB.first);
573 hard_map_[idAB]->settings.mode(
"Beams:idB", idAB.second);
576 logg[
LPythia].debug(
"Pythia object initialized with ", pdg_for_pythia[0],
577 " + ", pdg_for_pythia[1],
" at CM energy [GeV] ",
581 throw std::runtime_error(
"Pythia failed to initialize.");
587 logg[
LPythia].debug(
"hard_map_[", idAB.first,
"][", idAB.second,
588 "] : rndm is initialized with seed ", seed_new);
597 bool final_state_success =
hard_map_[idAB]->next();
598 logg[
LPythia].debug(
"Pythia final state computed, success = ",
599 final_state_success);
600 if (!final_state_success) {
604 ParticleList new_intermediate_particles;
605 ParticleList new_non_hadron_particles;
607 Pythia8::Vec4 pSum = 0.;
612 for (
int i = 0; i <
hard_map_[idAB]->event.size(); i++) {
613 if (
hard_map_[idAB]->event[i].isFinal()) {
614 const int pdgid =
hard_map_[idAB]->event[i].id();
615 Pythia8::Vec4 pquark =
hard_map_[idAB]->event[i].p();
616 const double mass =
hard_map_[idAB]->particleData.m0(pdgid);
618 const int status =
hard_map_[idAB]->event[i].status();
619 const int color =
hard_map_[idAB]->event[i].col();
620 const int anticolor =
hard_map_[idAB]->event[i].acol();
628 for (
int i = 0; i <
hard_map_[idAB]->event.sizeJunction(); i++) {
629 const int kind =
hard_map_[idAB]->event.kindJunction(i);
630 std::array<int, 3> col;
631 for (
int j = 0; j < 3; j++) {
632 col[j] =
hard_map_[idAB]->event.colJunction(i, j);
644 bool correct_constituents =
646 if (!correct_constituents) {
647 logg[
LPythia].debug(
"failed to find correct partonic constituents.");
653 while (ipart < npart) {
657 !
hard_map_[idAB]->particleData.isOctetHadron(pdgid)) {
658 logg[
LPythia].debug(
"PDG ID from Pythia: ", pdgid);
660 logg[
LPythia].debug(
"4-momentum from Pythia: ", momentum);
665 " does not exist in ParticleType - start over.");
666 final_state_success =
false;
675 bool hadronize_success =
false;
676 bool find_forward_string =
true;
677 logg[
LPythia].debug(
"Hard non-diff: partonic process gives ",
684 logg[
LPythia].debug(
" Dummy event in hard string routine failed.");
685 hadronize_success =
false;
702 logg[
LPythia].debug(
"Pythia hadronized, success = ", hadronize_success);
704 new_intermediate_particles.clear();
705 if (hadronize_success) {
706 for (
int i = 0; i < event_hadron.size(); i++) {
707 if (event_hadron[i].isFinal()) {
708 int pythia_id = event_hadron[i].id();
709 logg[
LPythia].debug(
"PDG ID from Pythia: ", pythia_id);
722 logg[
LPythia].debug(
"4-momentum from Pythia: ", momentum);
723 logg[
LPythia].debug(
"appending the particle ", pythia_id,
724 " to the intermediate particle list.");
725 bool found_ptype =
false;
726 if (event_hadron[i].isHadron()) {
728 new_intermediate_particles);
731 new_non_hadron_particles);
735 " does not exist in ParticleType - start over.");
736 hadronize_success =
false;
744 if (!hadronize_success) {
753 find_forward_string = !find_forward_string;
756 if (hadronize_success) {
759 data.set_cross_section_scaling_factor(1.);
767 return hadronize_success;
772 std::array<int, 5> &excess_quark,
773 std::array<int, 5> &excess_antiq) {
776 std::array<int, 3> qcontent_actual = pdg_actual.
quark_content();
777 std::array<int, 3> qcontent_mapped = pdg_mapped.
quark_content();
779 excess_quark = {0, 0, 0, 0, 0};
780 excess_antiq = {0, 0, 0, 0, 0};
781 for (
int i = 0; i < 3; i++) {
782 if (qcontent_actual[i] > 0) {
783 int j = qcontent_actual[i] - 1;
784 excess_quark[j] += 1;
787 if (qcontent_mapped[i] > 0) {
788 int j = qcontent_mapped[i] - 1;
789 excess_quark[j] -= 1;
792 if (qcontent_actual[i] < 0) {
793 int j = std::abs(qcontent_actual[i]) - 1;
794 excess_antiq[j] += 1;
797 if (qcontent_mapped[i] < 0) {
798 int j = std::abs(qcontent_mapped[i]) - 1;
799 excess_antiq[j] -= 1;
805 Pythia8::Particle &particle, std::array<int, 5> &excess_constituent) {
807 if (!particle.isQuark() && !particle.isDiquark()) {
812 const std::array<int, 5> excess_null = {0, 0, 0, 0, 0};
813 if (excess_constituent == excess_null) {
818 std::array<int, 2> pdgid = {0, 0};
821 if (particle.isQuark()) {
823 pdgid[0] = particle.id();
824 }
else if (particle.isDiquark()) {
829 for (
int iq = 0; iq < nq; iq++) {
830 int jq = std::abs(pdgid[iq]) - 1;
832 std::vector<int> k_found;
835 if (excess_constituent[jq] < 0) {
836 for (
int k = 0; k < 5; k++) {
838 if (k != jq && excess_constituent[k] > 0) {
839 k_found.push_back(k);
845 if (k_found.size() > 0) {
848 k_select = k_found[l];
851 pdgid[iq] = pdgid[iq] > 0 ? k_select + 1 : -(k_select + 1);
852 excess_constituent[jq] += 1;
853 excess_constituent[k_select] -= 1;
858 if (particle.isQuark()) {
859 pdgid_new = pdgid[0];
860 }
else if (particle.isDiquark()) {
861 if (std::abs(pdgid[0]) < std::abs(pdgid[1])) {
862 std::swap(pdgid[0], pdgid[1]);
865 pdgid_new = std::abs(pdgid[0]) * 1000 + std::abs(pdgid[1]) * 100;
866 if (std::abs(pdgid[0]) == std::abs(pdgid[1])) {
869 pdgid_new += spin_deg;
872 if (particle.id() < 0) {
876 logg[
LPythia].debug(
" parton id = ", particle.id(),
" is converted to ",
880 Pythia8::Vec4 pquark = particle.p();
882 double e_new = std::sqrt(mass_new * mass_new + pquark.pAbs() * pquark.pAbs());
884 particle.id(pdgid_new);
886 particle.m(mass_new);
890 Pythia8::Event &event_intermediate, std::array<int, 5> &nquark_total,
891 std::array<int, 5> &nantiq_total) {
892 for (
int iflav = 0; iflav < 5; iflav++) {
893 nquark_total[iflav] = 0;
894 nantiq_total[iflav] = 0;
897 for (
int ip = 1; ip < event_intermediate.size(); ip++) {
898 if (!event_intermediate[ip].isFinal()) {
901 const int pdgid = event_intermediate[ip].id();
904 for (
int iflav = 0; iflav < 5; iflav++) {
905 nquark_total[iflav] +=
910 for (
int iflav = 0; iflav < 5; iflav++) {
911 nantiq_total[iflav] +=
pythia_hadron_->particleData.nQuarksInCode(
912 std::abs(pdgid), iflav + 1);
919 Pythia8::Event &event_intermediate, std::array<int, 5> &nquark_total,
920 std::array<int, 5> &nantiq_total,
bool sign_constituent,
921 std::array<std::array<int, 5>, 2> &excess_constituent) {
922 Pythia8::Vec4 pSum = event_intermediate[0].p();
928 for (
int iflav = 0; iflav < 5; iflav++) {
935 excess_constituent[0][iflav] + excess_constituent[1][iflav];
936 if (sign_constituent) {
937 nquark_final += nquark_total[iflav];
939 nquark_final += nantiq_total[iflav];
944 bool enough_quark = nquark_final >= 0;
948 logg[
LPythia].debug(
" not enough constituents with flavor ", iflav + 1,
949 " : try to split a gluon to qqbar.");
950 for (
int ic = 0; ic < std::abs(nquark_final); ic++) {
954 if (excess_constituent[0][iflav] < 0) {
963 for (
int ip = 2; ip < event_intermediate.size(); ip++) {
964 if (!event_intermediate[ip].isFinal() ||
965 !event_intermediate[ip].isGluon()) {
969 const double y_gluon_current = event_intermediate[ip].y();
970 const double y_gluon_forward = event_intermediate[iforward].y();
971 if ((ih_mod == 0 && y_gluon_current > y_gluon_forward) ||
972 (ih_mod == 1 && y_gluon_current < y_gluon_forward)) {
977 if (!event_intermediate[iforward].isGluon()) {
978 logg[
LPythia].debug(
"There is no gluon to split into qqbar.");
983 Pythia8::Vec4 pgluon = event_intermediate[iforward].p();
985 const int pdgid = iflav + 1;
987 const int status = event_intermediate[iforward].status();
991 const int col = event_intermediate[iforward].col();
992 const int acol = event_intermediate[iforward].acol();
995 std::array<double, 2> px_quark;
996 std::array<double, 2> py_quark;
997 std::array<double, 2> pz_quark;
999 std::array<double, 2> e_quark;
1001 std::array<Pythia8::Vec4, 2> pquark;
1003 const double sigma_qt_frag =
pythia_hadron_->parm(
"StringPT:sigma");
1008 for (
int isign = 0; isign < 2; isign++) {
1012 px_quark[isign] = 0.5 * pgluon.px() + (isign == 0 ? 1. : -1.) * qx;
1013 py_quark[isign] = 0.5 * pgluon.py() + (isign == 0 ? 1. : -1.) * qy;
1014 pz_quark[isign] = 0.5 * pgluon.pz();
1016 std::sqrt(mass * mass + px_quark[isign] * px_quark[isign] +
1017 py_quark[isign] * py_quark[isign] +
1018 pz_quark[isign] * pz_quark[isign]);
1019 pquark[isign] = Pythia8::Vec4(px_quark[isign], py_quark[isign],
1020 pz_quark[isign], e_quark[isign]);
1025 pSum += pquark[0] + pquark[1] - pgluon;
1027 event_intermediate.append(pdgid, status, col, 0, pquark[0], mass);
1028 event_intermediate.append(-pdgid, status, 0, acol, pquark[1], mass);
1030 event_intermediate.remove(iforward, iforward);
1032 logg[
LPythia].debug(
" gluon at iforward = ", iforward,
1033 " is splitted into ", pdgid,
",", -pdgid,
1037 nquark_total[iflav] += 1;
1038 nantiq_total[iflav] += 1;
1045 event_intermediate[0].p(pSum);
1046 event_intermediate[0].m(pSum.mCalc());
1052 std::array<int, 5> &nquark_total,
1053 std::array<std::array<int, 5>, 2> &excess_quark,
1054 std::array<std::array<int, 5>, 2> &excess_antiq) {
1055 for (
int iflav = 0; iflav < 5; iflav++) {
1062 nquark_total[iflav] + excess_quark[0][iflav] + excess_quark[1][iflav];
1066 bool enough_quark = nquark_final >= 0;
1068 if (!enough_quark) {
1069 logg[
LPythia].debug(
" not enough constituents with flavor ", iflav + 1,
1070 " : try to modify excess of constituents.");
1071 for (
int ic = 0; ic < std::abs(nquark_final); ic++) {
1075 if (excess_quark[0][iflav] < 0) {
1083 excess_quark[ih_mod][iflav] += 1;
1084 excess_antiq[ih_mod][iflav] += 1;
1091 for (
int jflav = 0; jflav < 5; jflav++) {
1093 if (jflav != iflav && excess_quark[ih_mod][jflav] > 0) {
1096 excess_quark[ih_mod][jflav] -= 1;
1097 excess_antiq[ih_mod][jflav] -= 1;
1109 Pythia8::Event &event_intermediate,
1110 std::array<std::array<int, 5>, 2> &excess_quark,
1111 std::array<std::array<int, 5>, 2> &excess_antiq) {
1112 Pythia8::Vec4 pSum = event_intermediate[0].p();
1113 const double energy_init = pSum.e();
1114 logg[
LPythia].debug(
" initial total energy [GeV] : ", energy_init);
1117 std::array<int, 5> nquark_total;
1118 std::array<int, 5> nantiq_total;
1123 event_intermediate, nquark_total, nantiq_total,
true, excess_quark);
1125 event_intermediate, nquark_total, nantiq_total,
false, excess_antiq);
1129 if (!split_for_quark || !split_for_antiq) {
1135 for (
int iflav = 0; iflav < 5; iflav++) {
1136 if (nquark_total[iflav] + excess_quark[0][iflav] + excess_quark[1][iflav] <
1138 logg[
LPythia].debug(
"Not enough quark constituents of flavor ",
1143 if (nantiq_total[iflav] + excess_antiq[0][iflav] + excess_antiq[1][iflav] <
1145 logg[
LPythia].debug(
"Not enough antiquark constituents of flavor ",
1151 for (
int ih = 0; ih < 2; ih++) {
1152 logg[
LPythia].debug(
" initial excess_quark[", ih,
"] = (",
1153 excess_quark[ih][0],
", ", excess_quark[ih][1],
", ",
1154 excess_quark[ih][2],
", ", excess_quark[ih][3],
", ",
1155 excess_quark[ih][4],
")");
1156 logg[
LPythia].debug(
" initial excess_antiq[", ih,
"] = (",
1157 excess_antiq[ih][0],
", ", excess_antiq[ih][1],
", ",
1158 excess_antiq[ih][2],
", ", excess_antiq[ih][3],
", ",
1159 excess_antiq[ih][4],
")");
1162 bool recovered_quarks =
false;
1163 while (!recovered_quarks) {
1166 std::array<bool, 2> find_forward = {
true,
false};
1167 const std::array<int, 5> excess_null = {0, 0, 0, 0, 0};
1168 std::array<int, 5> excess_total = excess_null;
1170 for (
int ih = 0; ih < 2; ih++) {
1171 int nfrag = event_intermediate.size();
1172 for (
int np_end = 0; np_end < nfrag - 1; np_end++) {
1179 pSum -= event_intermediate[iforward].p();
1181 if (event_intermediate[iforward].
id() > 0) {
1184 " excess_quark[", ih,
"] = (", excess_quark[ih][0],
", ",
1185 excess_quark[ih][1],
", ", excess_quark[ih][2],
", ",
1186 excess_quark[ih][3],
", ", excess_quark[ih][4],
")");
1190 " excess_antiq[", ih,
"] = (", excess_antiq[ih][0],
", ",
1191 excess_antiq[ih][1],
", ", excess_antiq[ih][2],
", ",
1192 excess_antiq[ih][3],
", ", excess_antiq[ih][4],
")");
1195 const int pdgid = event_intermediate[iforward].id();
1196 Pythia8::Vec4 pquark = event_intermediate[iforward].p();
1199 const int status = event_intermediate[iforward].status();
1200 const int color = event_intermediate[iforward].col();
1201 const int anticolor = event_intermediate[iforward].acol();
1204 event_intermediate.append(pdgid, status, color, anticolor, pquark,
1207 event_intermediate.remove(iforward, iforward);
1213 for (
int j = 0; j < 5; j++) {
1214 excess_total[j] += (excess_quark[ih][j] - excess_antiq[ih][j]);
1220 recovered_quarks = excess_total == excess_null;
1222 logg[
LPythia].debug(
" valence quark contents of hadons are recovered.");
1224 logg[
LPythia].debug(
" current total energy [GeV] : ", pSum.e());
1228 if (std::abs(pSum.e() - energy_init) <=
1233 double energy_current = pSum.e();
1235 for (
int i = 1; i < event_intermediate.size(); i++) {
1236 slope += event_intermediate[i].pAbs2() / event_intermediate[i].e();
1239 const double rescale_factor = 1. + (energy_init - energy_current) / slope;
1241 for (
int i = 1; i < event_intermediate.size(); i++) {
1242 const double px = rescale_factor * event_intermediate[i].px();
1243 const double py = rescale_factor * event_intermediate[i].py();
1244 const double pz = rescale_factor * event_intermediate[i].pz();
1245 const double pabs = rescale_factor * event_intermediate[i].pAbs();
1246 const double mass = event_intermediate[i].m();
1248 event_intermediate[i].px(px);
1249 event_intermediate[i].py(py);
1250 event_intermediate[i].pz(pz);
1251 event_intermediate[i].e(std::sqrt(mass * mass + pabs * pabs));
1252 pSum += event_intermediate[i].p();
1254 logg[
LPythia].debug(
" parton momenta are rescaled by factor of ",
1258 logg[
LPythia].debug(
" final total energy [GeV] : ", pSum.e());
1261 event_intermediate[0].p(pSum);
1262 event_intermediate[0].m(pSum.mCalc());
1268 Pythia8::Event &event_intermediate,
1269 Pythia8::Event &event_hadronize) {
1270 Pythia8::Vec4 pSum = 0.;
1271 event_hadronize.reset();
1275 logg[
LPythia].debug(
"Hard non-diff: iforward = ", iforward,
"(",
1276 event_intermediate[iforward].
id(),
")");
1278 pSum += event_intermediate[iforward].p();
1279 event_hadronize.append(event_intermediate[iforward]);
1281 int col_to_find = event_intermediate[iforward].acol();
1282 int acol_to_find = event_intermediate[iforward].col();
1283 event_intermediate.remove(iforward, iforward);
1284 logg[
LPythia].debug(
"Hard non-diff: event_intermediate reduces in size to ",
1285 event_intermediate.size());
1288 while (col_to_find != 0 || acol_to_find != 0) {
1289 logg[
LPythia].debug(
" col_to_find = ", col_to_find,
1290 ", acol_to_find = ", acol_to_find);
1293 for (
int i = 1; i < event_intermediate.size(); i++) {
1294 const int pdgid = event_intermediate[i].id();
1296 col_to_find != 0 && col_to_find == event_intermediate[i].col();
1298 acol_to_find != 0 && acol_to_find == event_intermediate[i].acol();
1300 logg[
LPythia].debug(
" col_to_find ", col_to_find,
" from i ", i,
"(",
1304 logg[
LPythia].debug(
" acol_to_find ", acol_to_find,
" from i ", i,
"(",
1308 if (found_col && !found_acol) {
1310 col_to_find = event_intermediate[i].acol();
1312 }
else if (!found_col && found_acol) {
1314 acol_to_find = event_intermediate[i].col();
1316 }
else if (found_col && found_acol) {
1325 event_intermediate.list();
1326 event_intermediate.listJunctions();
1327 event_hadronize.list();
1328 event_hadronize.listJunctions();
1329 if (col_to_find != 0) {
1330 logg[
LPythia].error(
"No parton with col = ", col_to_find);
1332 if (acol_to_find != 0) {
1333 logg[
LPythia].error(
"No parton with acol = ", acol_to_find);
1335 throw std::runtime_error(
"Hard string could not be identified.");
1337 pSum += event_intermediate[ifound].p();
1339 event_hadronize.append(event_intermediate[ifound]);
1341 event_intermediate.remove(ifound, ifound);
1343 "Hard non-diff: event_intermediate reduces in size to ",
1344 event_intermediate.size());
1350 event_hadronize[0].p(pSum);
1351 event_hadronize[0].m(pSum.mCalc());
1355 Pythia8::Event &event_intermediate,
1356 Pythia8::Event &event_hadronize) {
1357 event_hadronize.reset();
1365 const int kind = event_intermediate.kindJunction(0);
1366 bool sign_color = kind % 2 == 1;
1367 std::vector<int> col;
1368 for (
int j = 0; j < 3; j++) {
1369 col.push_back(event_intermediate.colJunction(0, j));
1371 event_hadronize.appendJunction(kind, col[0], col[1], col[2]);
1372 event_intermediate.eraseJunction(0);
1373 logg[
LPythia].debug(
"junction (", col[0],
", ", col[1],
", ", col[2],
1374 ") with kind ", kind,
" will be handled.");
1376 bool found_string =
false;
1377 while (!found_string) {
1380 found_string =
true;
1381 for (
unsigned int j = 0; j < col.size(); j++) {
1382 found_string = found_string && col[j] == 0;
1384 if (!found_string) {
1387 logg[
LPythia].debug(
" still has leg(s) unfinished.");
1388 sign_color = !sign_color;
1389 std::vector<int> junction_to_move;
1390 for (
int i = 0; i < event_intermediate.sizeJunction(); i++) {
1391 const int kind_new = event_intermediate.kindJunction(i);
1395 if (sign_color != (kind_new % 2 == 1)) {
1399 std::array<int, 3> col_new;
1400 for (
int k = 0; k < 3; k++) {
1401 col_new[k] = event_intermediate.colJunction(i, k);
1404 int n_legs_connected = 0;
1406 for (
unsigned int j = 0; j < col.size(); j++) {
1410 for (
int k = 0; k < 3; k++) {
1411 if (col[j] == col_new[k]) {
1412 n_legs_connected += 1;
1420 if (n_legs_connected > 0) {
1421 for (
int k = 0; k < 3; k++) {
1422 if (col_new[k] != 0) {
1423 col.push_back(col_new[k]);
1427 event_intermediate.colJunction(i, 0),
", ",
1428 event_intermediate.colJunction(i, 1),
", ",
1429 event_intermediate.colJunction(i, 2),
1430 ") with kind ", kind_new,
" will be added.");
1431 junction_to_move.push_back(i);
1437 for (
unsigned int i = 0; i < junction_to_move.size(); i++) {
1438 unsigned int imove = junction_to_move[i] - i;
1439 const int kind_add = event_intermediate.kindJunction(imove);
1440 std::array<int, 3> col_add;
1441 for (
int k = 0; k < 3; k++) {
1442 col_add[k] = event_intermediate.colJunction(imove, k);
1445 event_hadronize.appendJunction(kind_add, col_add[0], col_add[1],
1448 event_intermediate.eraseJunction(imove);
1453 Pythia8::Vec4 pSum = event_hadronize[0].p();
1454 find_forward_string = pSum.pz() > 0.;
1458 Pythia8::Event &event_intermediate,
1459 Pythia8::Event &event_hadronize) {
1460 Pythia8::Vec4 pSum = event_hadronize[0].p();
1461 for (
unsigned int j = 0; j < col.size(); j++) {
1465 bool found_leg =
false;
1466 while (!found_leg) {
1468 for (
int i = 1; i < event_intermediate.size(); i++) {
1469 const int pdgid = event_intermediate[i].id();
1470 if (sign_color && col[j] == event_intermediate[i].col()) {
1471 logg[
LPythia].debug(
" col[", j,
"] = ", col[j],
" from i ", i,
"(",
1474 col[j] = event_intermediate[i].acol();
1476 }
else if (!sign_color && col[j] == event_intermediate[i].acol()) {
1477 logg[
LPythia].debug(
" acol[", j,
"] = ", col[j],
" from i ", i,
"(",
1480 col[j] = event_intermediate[i].col();
1487 if (event_intermediate.sizeJunction() == 0) {
1488 event_intermediate.list();
1489 event_intermediate.listJunctions();
1490 event_hadronize.list();
1491 event_hadronize.listJunctions();
1492 logg[
LPythia].error(
"No parton with col = ", col[j],
1493 " connected with junction leg ", j);
1494 throw std::runtime_error(
"Hard string could not be identified.");
1497 pSum += event_intermediate[ifound].p();
1499 event_hadronize.append(event_intermediate[ifound]);
1501 event_intermediate.remove(ifound, ifound);
1503 "Hard non-diff: event_intermediate reduces in size to ",
1504 event_intermediate.size());
1514 event_hadronize[0].p(pSum);
1515 event_hadronize[0].m(pSum.mCalc());
1520 const std::array<FourVector, 2> ustrcom = {
FourVector(1., 0., 0., 0.),
1534 std::swap(baryon, antibaryon);
1536 if (baryon.
baryon_number() != 1 || antibaryon.baryon_number() != -1) {
1537 throw std::invalid_argument(
"Expected baryon-antibaryon pair.");
1541 constexpr
int n_q_types = 5;
1542 std::vector<int> qcount_bar, qcount_antibar;
1543 std::vector<int> n_combinations;
1544 bool no_combinations =
true;
1545 for (
int i = 0; i < n_q_types; i++) {
1547 qcount_antibar.push_back(-antibaryon.net_quark_number(i + 1));
1548 const int n_i = qcount_bar[i] * qcount_antibar[i];
1549 n_combinations.push_back(n_i);
1551 no_combinations =
false;
1557 if (no_combinations) {
1558 for (
int i = 0; i < 2; i++) {
1572 const int q_annihilate = discrete_distr() + 1;
1573 qcount_bar[q_annihilate - 1]--;
1574 qcount_antibar[q_annihilate - 1]--;
1577 std::vector<int> remaining_quarks, remaining_antiquarks;
1578 for (
int i = 0; i < n_q_types; i++) {
1579 for (
int j = 0; j < qcount_bar[i]; j++) {
1580 remaining_quarks.push_back(i + 1);
1582 for (
int j = 0; j < qcount_antibar[i]; j++) {
1583 remaining_antiquarks.push_back(-(i + 1));
1586 assert(remaining_quarks.size() == 2);
1587 assert(remaining_antiquarks.size() == 2);
1593 std::swap(remaining_quarks[0], remaining_quarks[1]);
1596 std::swap(remaining_antiquarks[0], remaining_antiquarks[1]);
1599 bool kin_threshold_satisfied =
true;
1600 for (
int i = 0; i < 2; i++) {
1601 const double mstr_min =
1604 if (mstr_min > mstr[i]) {
1605 kin_threshold_satisfied =
false;
1608 if (!kin_threshold_satisfied) {
1612 for (
int i = 0; i < 2; i++) {
1613 ParticleList new_intermediate_particles;
1617 fragment_string(remaining_quarks[i], remaining_antiquarks[i], mstr[i],
1618 evec,
true,
false, new_intermediate_particles);
1631 ThreeVector &evec_polar, std::array<ThreeVector, 3> &evec_basis) {
1634 if (std::abs(evec_polar.
x3()) < (1. - 1.0e-8)) {
1639 evec_basis[0] = evec_polar;
1641 theta = std::acos(evec_basis[0].x3());
1643 ex = evec_basis[0].x1();
1644 ey = evec_basis[0].x2();
1645 et = std::sqrt(ex * ex + ey * ey);
1647 phi = std::acos(ex / et);
1649 phi = -std::acos(ex / et);
1654 evec_basis[1].set_x1(std::cos(theta) * std::cos(phi));
1655 evec_basis[1].set_x2(std::cos(theta) * std::sin(phi));
1656 evec_basis[1].set_x3(-std::sin(theta));
1658 evec_basis[2].set_x1(-std::sin(phi));
1659 evec_basis[2].set_x2(std::cos(phi));
1660 evec_basis[2].set_x3(0.);
1663 if (evec_polar.
x3() > 0.) {
1674 assert(std::fabs(evec_basis[1] * evec_basis[2]) <
really_small);
1675 assert(std::fabs(evec_basis[2] * evec_basis[0]) <
really_small);
1676 assert(std::fabs(evec_basis[0] * evec_basis[1]) <
really_small);
1689 assert((std::abs(diquark) > 1000) && (std::abs(diquark) < 5510) &&
1690 (std::abs(diquark) % 100 < 10));
1693 deg_spin = std::abs(diquark) % 10;
1695 const int sign_anti = diquark > 0 ? 1 : -1;
1698 q1 = sign_anti * (std::abs(diquark) - (std::abs(diquark) % 1000)) / 1000;
1699 q2 = sign_anti * (std::abs(diquark) % 1000 - deg_spin) / 100;
1703 assert((q1 > 0 && q2 > 0) || (q1 < 0 && q2 < 0));
1704 if (std::abs(q1) < std::abs(q2)) {
1707 int diquark = std::abs(q1 * 1000 + q2 * 100);
1712 return (q1 < 0) ? -diquark : diquark;
1759 std::swap(idq1, idq2);
1765 bool separate_fragment_baryon,
1766 ParticleList &intermediate_particles) {
1768 intermediate_particles.clear();
1770 logg[
LPythia].debug(
"initial quark content for fragment_string : ", idq1,
1772 logg[
LPythia].debug(
"initial string mass (GeV) for fragment_string : ",
1775 std::array<int, 2> idqIn;
1781 std::array<double, 2> m_const;
1783 for (
int i = 0; i < 2; i++) {
1785 bstring +=
pythia_hadron_->particleData.baryonNumberType(idqIn[i]);
1789 logg[
LPythia].debug(
"baryon number of string times 3 : ", bstring);
1796 evecLong = -evecLong;
1799 if (m_const[0] + m_const[1] > mString) {
1800 throw std::runtime_error(
"String fragmentation: m1 + m2 > mString");
1802 Pythia8::Vec4 pSum = 0.;
1804 int number_of_fragments = 0;
1805 bool do_string_fragmentation =
false;
1809 double ppos_string_new, pneg_string_new;
1812 double QTrx_string_new, QTry_string_new, QTrn_string_new;
1814 double mTrn_string_new;
1816 double mass_string_new;
1820 double QTrx_add_pos, QTry_add_pos;
1823 double QTrx_add_neg, QTry_add_neg;
1835 std::array<ThreeVector, 3> evec_basis;
1838 if (separate_fragment_baryon && (std::abs(bstring) == 3) &&
1839 (mString > m_const[0] + m_const[1] + 1.)) {
1846 std::vector<int> pdgid_frag_prior;
1849 std::vector<FourVector> momentum_frag_prior;
1852 double QTrx_string_pos;
1854 double QTrx_string_neg;
1856 double QTry_string_pos;
1858 double QTry_string_neg;
1861 double QTrn_string_pos;
1864 double QTrn_string_neg;
1866 std::array<double, 2> m_trans;
1869 const int niter_max = 10000;
1870 bool found_leading_baryon =
false;
1871 for (
int iiter = 0; iiter < niter_max; iiter++) {
1873 pdgid_frag_prior.clear();
1874 momentum_frag_prior.clear();
1876 std::vector<int> pdgid_frag;
1877 std::vector<FourVector> momentum_frag;
1879 ppos_string_new = mString * M_SQRT1_2;
1880 pneg_string_new = mString * M_SQRT1_2;
1882 QTrx_string_pos = 0.;
1883 QTrx_string_neg = 0.;
1884 QTrx_string_new = 0.;
1885 QTry_string_pos = 0.;
1886 QTry_string_neg = 0.;
1887 QTry_string_new = 0.;
1889 Pythia8::FlavContainer flav_string_pos =
1890 bstring > 0 ? Pythia8::FlavContainer(idq2)
1891 : Pythia8::FlavContainer(idq1);
1893 Pythia8::FlavContainer flav_string_neg =
1894 bstring > 0 ? Pythia8::FlavContainer(idq1)
1895 : Pythia8::FlavContainer(idq2);
1897 bool found_forward_baryon =
false;
1899 bool done_forward_end =
false;
1902 bool energy_used_up =
false;
1903 while (!found_forward_baryon && !energy_used_up) {
1914 separate_fragment_baryon && from_forward && !done_forward_end,
1915 evec_basis, ppos_string_new, pneg_string_new, QTrx_string_pos,
1916 QTrx_string_neg, QTry_string_pos, QTry_string_neg, flav_string_pos,
1917 flav_string_neg, pdgid_frag, momentum_frag);
1923 QTrx_string_new = QTrx_string_pos + QTrx_string_neg;
1924 QTry_string_new = QTry_string_pos + QTry_string_neg;
1928 idqIn[0] = bstring > 0 ? flav_string_neg.id : flav_string_pos.id;
1929 idqIn[1] = bstring > 0 ? flav_string_pos.id : flav_string_neg.id;
1930 for (
int i = 0; i < 2; i++) {
1933 QTrn_string_pos = std::sqrt(QTrx_string_pos * QTrx_string_pos +
1934 QTry_string_pos * QTry_string_pos);
1935 QTrn_string_neg = std::sqrt(QTrx_string_neg * QTrx_string_neg +
1936 QTry_string_neg * QTry_string_neg);
1941 m_trans[0] = std::sqrt(m_const[0] * m_const[0] +
1942 QTrn_string_neg * QTrn_string_neg);
1946 m_trans[1] = std::sqrt(m_const[1] * m_const[1] +
1947 QTrn_string_pos * QTrn_string_pos);
1952 m_trans[0] = std::sqrt(m_const[0] * m_const[0] +
1953 QTrn_string_pos * QTrn_string_pos);
1957 m_trans[1] = std::sqrt(m_const[1] * m_const[1] +
1958 QTrn_string_neg * QTrn_string_neg);
1960 done_forward_end = done_forward_end || from_forward;
1961 found_forward_baryon =
1962 found_forward_baryon ||
1967 energy_used_up =
true;
1971 n_frag_prior += n_frag;
1972 for (
int i_frag = 0; i_frag < n_frag; i_frag++) {
1973 pdgid_frag_prior.push_back(pdgid_frag[i_frag]);
1974 momentum_frag_prior.push_back(momentum_frag[i_frag]);
1982 double mTsqr_string = 2. * ppos_string_new * pneg_string_new;
1983 mTrn_string_new = std::sqrt(mTsqr_string);
1984 QTrn_string_new = std::sqrt(QTrx_string_new * QTrx_string_new +
1985 QTry_string_new * QTry_string_new);
1986 if (mTrn_string_new < QTrn_string_new) {
1989 found_leading_baryon =
false;
1993 std::sqrt(mTsqr_string - QTrn_string_new * QTrn_string_new);
1997 if (mass_string_new > m_const[0] + m_const[1]) {
1998 do_string_fragmentation =
true;
1999 found_leading_baryon =
true;
2000 QTrx_add_pos = QTrx_string_pos;
2001 QTry_add_pos = QTry_string_pos;
2002 QTrx_add_neg = QTrx_string_neg;
2003 QTry_add_neg = QTry_string_neg;
2005 found_leading_baryon =
false;
2008 }
else if (n_frag == 2) {
2011 do_string_fragmentation =
false;
2012 found_leading_baryon =
true;
2016 if (found_leading_baryon) {
2020 if (found_leading_baryon) {
2023 for (
int i_frag = 0; i_frag < n_frag_prior; i_frag++) {
2024 logg[
LPythia].debug(
"appending the the fragmented hadron ",
2025 pdgid_frag_prior[i_frag],
2026 " to the intermediate particle list.");
2029 momentum_frag_prior[i_frag],
2030 intermediate_particles);
2032 logg[
LPythia].error(
"PDG ID ", pdgid_frag_prior[i_frag],
2033 " should exist in ParticleType.");
2034 throw std::runtime_error(
"string fragmentation failed.");
2036 number_of_fragments++;
2044 if (do_string_fragmentation) {
2045 mTrn_string_new = std::sqrt(2. * ppos_string_new * pneg_string_new);
2047 std::array<double, 2> ppos_parton;
2049 std::array<double, 2> pneg_parton;
2057 const double pb_const =
2058 (mTrn_string_new * mTrn_string_new + m_trans[0] * m_trans[0] -
2059 m_trans[1] * m_trans[1]) /
2060 (4. * pneg_string_new);
2061 const double pc_const =
2062 0.5 * m_trans[0] * m_trans[0] * ppos_string_new / pneg_string_new;
2063 ppos_parton[0] = pb_const + (bstring > 0 ? -1. : 1.) *
2064 std::sqrt(pb_const * pb_const - pc_const);
2065 ppos_parton[1] = ppos_string_new - ppos_parton[0];
2069 for (
int i = 0; i < 2; i++) {
2070 pneg_parton[i] = 0.5 * m_trans[i] * m_trans[i] / ppos_parton[i];
2073 const int status = 1;
2074 int color, anticolor;
2077 Pythia8::Vec4 pquark;
2097 bstring > 0 ? evec_basis[1] * (QTrx_string_neg - QTrx_add_neg) +
2098 evec_basis[2] * (QTry_string_neg - QTry_add_neg)
2099 : evec_basis[1] * (QTrx_string_pos - QTrx_add_pos) +
2100 evec_basis[2] * (QTry_string_pos - QTry_add_pos);
2102 evec_basis[0] * (ppos_parton[0] - pneg_parton[0]) * M_SQRT1_2 +
2104 const double E_quark =
2105 std::sqrt(m_const[0] * m_const[0] + three_mom.
sqr());
2106 pquark =
set_Vec4(E_quark, three_mom);
2108 pythia_hadron_->event.append(idqIn[0], status, color, anticolor, pquark,
2129 bstring > 0 ? evec_basis[1] * (QTrx_string_pos - QTrx_add_pos) +
2130 evec_basis[2] * (QTry_string_pos - QTry_add_pos)
2131 : evec_basis[1] * (QTrx_string_neg - QTrx_add_neg) +
2132 evec_basis[2] * (QTry_string_neg - QTry_add_neg);
2134 evec_basis[0] * (ppos_parton[1] - pneg_parton[1]) * M_SQRT1_2 +
2136 const double E_antiq =
2137 std::sqrt(m_const[1] * m_const[1] + three_mom.
sqr());
2138 pquark =
set_Vec4(E_antiq, three_mom);
2140 pythia_hadron_->event.append(idqIn[1], status, color, anticolor, pquark,
2144 do_string_fragmentation =
true;
2146 ppos_string_new = mString * M_SQRT1_2;
2147 pneg_string_new = mString * M_SQRT1_2;
2148 QTrx_string_new = 0.;
2149 QTry_string_new = 0.;
2150 QTrn_string_new = 0.;
2151 mTrn_string_new = mString;
2152 mass_string_new = mString;
2157 double sign_direction = 1.;
2158 if (bstring == -3) {
2162 sign_direction = -1;
2166 const double pCMquark =
pCM(mString, m_const[0], m_const[1]);
2167 const double E1 = std::sqrt(m_const[0] * m_const[0] + pCMquark * pCMquark);
2168 const double E2 = std::sqrt(m_const[1] * m_const[1] + pCMquark * pCMquark);
2170 ThreeVector direction = sign_direction * evecLong;
2173 const int status1 = 1, color1 = 1, anticolor1 = 0;
2174 Pythia8::Vec4 pquark =
set_Vec4(E1, -direction * pCMquark);
2176 pythia_hadron_->event.append(idqIn[0], status1, color1, anticolor1, pquark,
2179 const int status2 = 1, color2 = 0, anticolor2 = 1;
2180 pquark =
set_Vec4(E2, direction * pCMquark);
2182 pythia_hadron_->event.append(idqIn[1], status2, color2, anticolor2, pquark,
2186 if (do_string_fragmentation) {
2187 logg[
LPythia].debug(
"fragmenting a string with ", idqIn[0],
", ", idqIn[1]);
2193 if (!successful_hadronization) {
2200 pythia_hadron_->event, evec_basis, ppos_string_new, pneg_string_new,
2201 QTrx_string_new, QTry_string_new, QTrx_add_pos, QTry_add_pos,
2202 QTrx_add_neg, QTry_add_neg);
2203 if (!successful_kinematics) {
2207 for (
int ipyth = 0; ipyth <
pythia_hadron_->event.size(); ipyth++) {
2218 logg[
LPythia].debug(
"appending the fragmented hadron ", pythia_id,
2219 " to the intermediate particle list.");
2224 " does not exist in ParticleType - start over.");
2225 intermediate_particles.clear();
2229 number_of_fragments++;
2232 return number_of_fragments;
2236 bool from_forward,
bool separate_fragment_baryon,
2237 std::array<ThreeVector, 3> &evec_basis,
double &ppos_string,
2238 double &pneg_string,
double &QTrx_string_pos,
double &QTrx_string_neg,
2239 double &QTry_string_pos,
double &QTry_string_neg,
2240 Pythia8::FlavContainer &flav_string_pos,
2241 Pythia8::FlavContainer &flav_string_neg, std::vector<int> &pdgid_frag,
2242 std::vector<FourVector> &momentum_frag) {
2245 const int n_try = 10;
2247 momentum_frag.clear();
2249 if (ppos_string < 0. || pneg_string < 0.) {
2250 throw std::runtime_error(
"string has a negative lightcone momentum.");
2252 double mTsqr_string = 2. * ppos_string * pneg_string;
2254 double mTrn_string = std::sqrt(mTsqr_string);
2256 double QTrx_string_tot = QTrx_string_pos + QTrx_string_neg;
2257 double QTry_string_tot = QTry_string_pos + QTry_string_neg;
2258 double QTsqr_string_tot = std::fabs(QTrx_string_tot * QTrx_string_tot) +
2259 std::fabs(QTry_string_tot * QTry_string_tot);
2260 double QTrn_string_tot = std::sqrt(QTsqr_string_tot);
2261 if (mTrn_string < QTrn_string_tot) {
2265 double mass_string = std::sqrt(mTsqr_string - QTsqr_string_tot);
2266 logg[
LPythia].debug(
" Fragment off one hadron from a string ( ",
2267 flav_string_pos.id,
" , ", flav_string_neg.id,
2268 " ) with mass ", mass_string,
" GeV.");
2271 const double sigma_qt_frag =
pythia_hadron_->parm(
"StringPT:sigma");
2272 const double stop_string_mass =
2274 const double stop_string_smear =
2278 const double prob_enhance_qt =
2280 double fac_enhance_qt;
2284 fac_enhance_qt = 1.;
2298 logg[
LPythia].debug(
" Transverse momentum (", QTrx_new,
", ", QTry_new,
2299 ") GeV selected for the new qqbar pair.");
2308 double QTrx_had_1st =
2309 from_forward ? QTrx_string_pos + QTrx_new : QTrx_string_neg + QTrx_new;
2310 double QTry_had_1st =
2311 from_forward ? QTry_string_pos + QTry_new : QTry_string_neg + QTry_new;
2312 double QTrn_had_1st =
2313 std::sqrt(QTrx_had_1st * QTrx_had_1st + QTry_had_1st * QTry_had_1st);
2316 int pdgid_had_1st = 0;
2318 double mass_had_1st = 0.;
2321 Pythia8::FlavContainer flav_old =
2322 from_forward ? flav_string_pos : flav_string_neg;
2327 Pythia8::FlavContainer flav_new = Pythia8::FlavContainer(0);
2331 for (
int i_try = 0; i_try < n_try; i_try++) {
2336 if (pdgid_had_1st != 0) {
2339 logg[
LPythia].debug(
" number of tries of flavor selection : ",
2340 i_try + 1,
" in StringProcess::fragment_off_hadron.");
2344 if (pdgid_had_1st == 0) {
2348 " selected for the string end with ", flav_old.id);
2350 " selected for the (first) fragmented hadron.");
2351 bool had_1st_baryon =
pythia_hadron_->particleData.isBaryon(pdgid_had_1st);
2353 double mTrn_had_1st =
2354 std::sqrt(mass_had_1st * mass_had_1st + QTrn_had_1st * QTrn_had_1st);
2355 logg[
LPythia].debug(
" Transverse momentum (", QTrx_had_1st,
", ",
2357 ") GeV selected for the (first) fragmented hadron.");
2362 const double mass_min_to_continue =
2363 (stop_string_mass +
pythia_hadron_->particleData.m0(flav_new.id) +
2369 bool string_into_final_two = mass_string < mass_min_to_continue;
2370 if (string_into_final_two) {
2371 logg[
LPythia].debug(
" The string mass is below the mass threshold ",
2372 mass_min_to_continue,
2373 " GeV : finishing with two hadrons.");
2377 double ppos_had_1st = 0.;
2378 double pneg_had_1st = 0.;
2382 bool from_diquark_end =
2383 from_forward ?
pythia_hadron_->particleData.isDiquark(flav_string_pos.id)
2386 bool has_diquark_pos =
2390 if (string_into_final_two) {
2394 int pdgid_had_2nd = 0.;
2396 double mass_had_2nd = 0.;
2399 Pythia8::FlavContainer flav_new2 = Pythia8::FlavContainer(0);
2400 flav_new2.anti(flav_new);
2403 if (
pythia_hadron_->particleData.isDiquark(flav_string_neg.id) &&
2404 pythia_hadron_->particleData.isDiquark(flav_new2.id) && from_forward) {
2407 if (
pythia_hadron_->particleData.isDiquark(flav_string_pos.id) &&
2408 pythia_hadron_->particleData.isDiquark(flav_new2.id) && !from_forward) {
2411 for (
int i_try = 0; i_try < n_try; i_try++) {
2416 if (pdgid_had_2nd != 0) {
2422 if (pdgid_had_2nd == 0) {
2426 " selected for the (second) fragmented hadron.");
2427 bool had_2nd_baryon =
pythia_hadron_->particleData.isBaryon(pdgid_had_2nd);
2435 double QTrx_had_2nd =
2436 from_forward ? QTrx_string_neg - QTrx_new : QTrx_string_pos - QTrx_new;
2437 double QTry_had_2nd =
2438 from_forward ? QTry_string_neg - QTry_new : QTry_string_pos - QTry_new;
2439 double QTrn_had_2nd =
2440 std::sqrt(QTrx_had_2nd * QTrx_had_2nd + QTry_had_2nd * QTry_had_2nd);
2441 double mTrn_had_2nd =
2442 std::sqrt(mass_had_2nd * mass_had_2nd + QTrn_had_2nd * QTrn_had_2nd);
2443 logg[
LPythia].debug(
" Transverse momentum (", QTrx_had_2nd,
", ",
2445 ") GeV selected for the (second) fragmented hadron.");
2447 double ppos_had_2nd = 0.;
2448 double pneg_had_2nd = 0.;
2454 bool found_kinematics =
2457 separate_fragment_baryon && has_diquark_pos && had_1st_baryon,
2458 ppos_string, pneg_string, mTrn_had_1st, mTrn_had_2nd,
2459 ppos_had_1st, ppos_had_2nd, pneg_had_1st, pneg_had_2nd)
2461 separate_fragment_baryon && has_diquark_pos && had_2nd_baryon,
2462 ppos_string, pneg_string, mTrn_had_2nd, mTrn_had_1st,
2463 ppos_had_2nd, ppos_had_1st, pneg_had_2nd, pneg_had_1st);
2464 if (!found_kinematics) {
2471 QTrx_string_pos = 0.;
2472 QTry_string_pos = 0.;
2475 pdgid_frag.push_back(pdgid_had_1st);
2477 (ppos_had_1st + pneg_had_1st) * M_SQRT1_2,
2478 evec_basis[0] * (ppos_had_1st - pneg_had_1st) * M_SQRT1_2 +
2479 evec_basis[1] * QTrx_had_1st + evec_basis[2] * QTry_had_1st);
2480 momentum_frag.push_back(mom_had_1st);
2483 pdgid_frag.push_back(pdgid_had_2nd);
2485 (ppos_had_2nd + pneg_had_2nd) * M_SQRT1_2,
2486 evec_basis[0] * (ppos_had_2nd - pneg_had_2nd) * M_SQRT1_2 +
2487 evec_basis[1] * QTrx_had_2nd + evec_basis[2] * QTry_had_2nd);
2488 momentum_frag.push_back(mom_had_2nd);
2497 double stringz_a_use, stringz_b_use;
2500 if (separate_fragment_baryon && from_diquark_end && had_1st_baryon) {
2510 double xfrac =
sample_zLund(stringz_a_use, stringz_b_use, mTrn_had_1st);
2514 ppos_had_1st = xfrac * ppos_string;
2515 pneg_had_1st = 0.5 * mTrn_had_1st * mTrn_had_1st / ppos_had_1st;
2516 if (pneg_had_1st > pneg_string) {
2522 pneg_had_1st = xfrac * pneg_string;
2523 ppos_had_1st = 0.5 * mTrn_had_1st * mTrn_had_1st / pneg_had_1st;
2524 if (ppos_had_1st > ppos_string) {
2530 pdgid_frag.push_back(pdgid_had_1st);
2532 (ppos_had_1st + pneg_had_1st) * M_SQRT1_2,
2533 evec_basis[0] * (ppos_had_1st - pneg_had_1st) * M_SQRT1_2 +
2534 evec_basis[1] * QTrx_had_1st + evec_basis[2] * QTry_had_1st);
2535 momentum_frag.push_back(mom_had_1st);
2538 ppos_string -= ppos_had_1st;
2539 pneg_string -= pneg_had_1st;
2549 flav_string_pos.anti(flav_new);
2550 QTrx_string_pos = -QTrx_new;
2551 QTry_string_pos = -QTry_new;
2555 flav_string_neg.anti(flav_new);
2556 QTrx_string_neg = -QTrx_new;
2557 QTry_string_neg = -QTry_new;
2567 const int baryon_number =
2571 int pdgid_hadron = 0;
2574 Pythia8::FlavContainer flav1 = Pythia8::FlavContainer(idq1);
2575 Pythia8::FlavContainer flav2 = Pythia8::FlavContainer(idq2);
2576 const int n_try = 10;
2577 for (
int i_try = 0; i_try < n_try; i_try++) {
2579 if (pdgid_hadron != 0) {
2580 return pdgid_hadron;
2588 std::array<int, 5> frag_net_q;
2591 for (
int iq = 0; iq < 5; iq++) {
2593 pythia_hadron_->particleData.nQuarksInCode(std::abs(idq1), iq + 1);
2595 pythia_hadron_->particleData.nQuarksInCode(std::abs(idq2), iq + 1);
2596 nq1 = idq1 > 0 ? nq1 : -nq1;
2597 nq2 = idq2 > 0 ? nq2 : -nq2;
2598 frag_net_q[iq] = nq1 + nq2;
2600 const int frag_iso3 = frag_net_q[1] - frag_net_q[0];
2601 const int frag_strange = -frag_net_q[2];
2602 const int frag_charm = frag_net_q[3];
2603 const int frag_bottom = -frag_net_q[4];
2604 logg[
LPythia].debug(
" conserved charges : iso3 = ", frag_iso3,
2605 ", strangeness = ", frag_strange,
2606 ", charmness = ", frag_charm,
2607 ", bottomness = ", frag_bottom);
2609 std::vector<int> pdgid_possible;
2610 std::vector<double> weight_possible;
2611 std::vector<double> weight_summed;
2616 if (!ptype.is_hadron()) {
2619 const int pdgid = ptype.pdgcode().get_decimal();
2621 (baryon_number == 3 * ptype.pdgcode().baryon_number()) &&
2622 (frag_iso3 == ptype.pdgcode().isospin3()) &&
2623 (frag_strange == ptype.pdgcode().strangeness()) &&
2624 (frag_charm == ptype.pdgcode().charmness()) &&
2625 (frag_bottom == ptype.pdgcode().bottomness())) {
2626 const int spin_degeneracy = ptype.pdgcode().spin_degeneracy();
2627 const double mass_pole = ptype.mass();
2628 const double weight =
static_cast<double>(spin_degeneracy) / mass_pole;
2629 pdgid_possible.push_back(pdgid);
2630 weight_possible.push_back(weight);
2632 logg[
LPythia].debug(
" PDG id ", pdgid,
" is possible with weight ",
2636 const int n_possible = pdgid_possible.size();
2637 weight_summed.push_back(0.);
2638 for (
int i = 0; i < n_possible; i++) {
2639 weight_summed.push_back(weight_summed[i] + weight_possible[i]);
2645 for (
int i = 0; i < n_possible; i++) {
2646 if ((uspc >= weight_summed[i]) && (uspc < weight_summed[i + 1])) {
2647 return pdgid_possible[i];
2664 bool end1_is_quark = idq1 > 0 &&
pythia_hadron_->particleData.isQuark(idq1);
2665 bool end1_is_antidiq =
2668 bool end2_is_antiq = idq2 < 0 &&
pythia_hadron_->particleData.isQuark(idq2);
2669 bool end2_is_diquark =
2673 if (end1_is_quark) {
2674 if (end2_is_antiq) {
2677 }
else if (end2_is_diquark) {
2683 }
else if (end1_is_antidiq) {
2684 if (end2_is_antiq) {
2697 std::array<int, 5> net_qnumber;
2698 for (
int iflav = 0; iflav < 5; iflav++) {
2699 net_qnumber[iflav] = 0;
2702 pythia_hadron_->particleData.nQuarksInCode(std::abs(idq1), iflav + 1);
2705 qnumber1 = -qnumber1;
2707 net_qnumber[iflav] += qnumber1;
2710 pythia_hadron_->particleData.nQuarksInCode(std::abs(idq2), iflav + 1);
2713 qnumber2 = -qnumber2;
2715 net_qnumber[iflav] += qnumber2;
2719 std::vector<int> pdgid_possible;
2721 std::vector<double> mass_diff;
2723 if (!ptype.is_hadron() || ptype.is_stable() ||
2724 ptype.pdgcode().baryon_number() != baryon) {
2728 const int pdgid = ptype.pdgcode().get_decimal();
2729 const double mass_min = ptype.min_mass_spectral();
2730 if (mass < mass_min) {
2735 if (ptype.pdgcode().isospin3() != net_qnumber[1] - net_qnumber[0]) {
2739 if (ptype.pdgcode().strangeness() != -net_qnumber[2]) {
2743 if (ptype.pdgcode().charmness() != net_qnumber[3]) {
2747 if (ptype.pdgcode().bottomness() != -net_qnumber[4]) {
2752 const double mass_pole = ptype.mass();
2754 pdgid_possible.push_back(pdgid);
2755 mass_diff.push_back(mass - mass_pole);
2758 const int n_res = pdgid_possible.size();
2764 int ires_closest = 0;
2765 double mass_diff_min = std::fabs(mass_diff[0]);
2768 for (
int ires = 1; ires < n_res; ires++) {
2769 if (std::fabs(mass_diff[ires]) < mass_diff_min) {
2770 ires_closest = ires;
2771 mass_diff_min = mass_diff[ires];
2774 logg[
LPythia].debug(
"Quark constituents ", idq1,
" and ", idq2,
" with mass ",
2775 mass,
" (GeV) turned into a resonance ",
2776 pdgid_possible[ires_closest]);
2777 return pdgid_possible[ires_closest];
2781 bool separate_fragment_hadron,
double ppos_string,
double pneg_string,
2782 double mTrn_had_forward,
double mTrn_had_backward,
double &ppos_had_forward,
2783 double &ppos_had_backward,
double &pneg_had_forward,
2784 double &pneg_had_backward) {
2785 const double mTsqr_string = 2. * ppos_string * pneg_string;
2786 if (mTsqr_string < 0.) {
2789 const double mTrn_string = std::sqrt(mTsqr_string);
2790 if (mTrn_string < mTrn_had_forward + mTrn_had_backward) {
2795 const double mTsqr_had_forward = mTrn_had_forward * mTrn_had_forward;
2797 const double mTsqr_had_backward = mTrn_had_backward * mTrn_had_backward;
2811 const double xm_diff =
2812 (mTsqr_had_forward - mTsqr_had_backward) / mTsqr_string;
2813 const double xe_pos = 0.5 * (1. + xm_diff);
2814 const double xe_neg = 0.5 * (1. - xm_diff);
2817 const double lambda_sqr =
2818 pow_int(mTsqr_string - mTsqr_had_forward - mTsqr_had_backward, 2) -
2819 4. * mTsqr_had_forward * mTsqr_had_backward;
2820 if (lambda_sqr <= 0.) {
2823 const double lambda = std::sqrt(lambda_sqr);
2824 const double b_lund =
2829 const double prob_reverse =
2830 std::exp(-b_lund * lambda) / (1. + std::exp(-b_lund * lambda));
2831 double xpz_pos = 0.5 * lambda / mTsqr_string;
2836 ppos_had_forward = (xe_pos + xpz_pos) * ppos_string;
2837 ppos_had_backward = (xe_neg - xpz_pos) * ppos_string;
2839 pneg_had_forward = 0.5 * mTsqr_had_forward / ppos_had_forward;
2840 pneg_had_backward = 0.5 * mTsqr_had_backward / ppos_had_backward;
2848 bool xfrac_accepted =
false;
2856 while (!xfrac_accepted) {
2857 const double fac_env = b * mTrn * mTrn;
2861 const double xfrac_inv = 1. - std::log(u_aux) / fac_env;
2862 assert(xfrac_inv >= 1.);
2865 const double xf_ratio = std::pow(1. - 1. / xfrac_inv, a) / xfrac_inv;
2870 xfrac = 1. / xfrac_inv;
2871 xfrac_accepted =
true;
2878 Pythia8::Event &event_fragments, std::array<ThreeVector, 3> &evec_basis,
2879 double ppos_string,
double pneg_string,
double QTrx_string,
2880 double QTry_string,
double QTrx_add_pos,
double QTry_add_pos,
2881 double QTrx_add_neg,
double QTry_add_neg) {
2882 logg[
LPythia].debug(
"Correcting the kinematics of fragmented hadrons...");
2884 if (ppos_string < 0. || pneg_string < 0.) {
2886 " wrong lightcone momenta of string : ppos_string (GeV) = ",
2887 ppos_string,
" pneg_string (GeV) = ", pneg_string);
2891 const double yrapid_string = 0.5 * std::log(ppos_string / pneg_string);
2892 logg[
LOutput].debug(
"Momentum-space rapidity of the string should be ",
2896 const double mTrn_string = std::sqrt(2. * ppos_string * pneg_string);
2897 logg[
LOutput].debug(
"Transvere mass (GeV) of the string should be ",
2900 const double QTrn_string =
2901 std::sqrt(QTrx_string * QTrx_string + QTry_string * QTry_string);
2902 if (mTrn_string < QTrn_string) {
2904 " wrong transverse mass of string : mTrn_string (GeV) = ", mTrn_string,
2905 " QTrn_string (GeV) = ", QTrn_string);
2908 const double msqr_string =
2909 mTrn_string * mTrn_string - QTrn_string * QTrn_string;
2911 const double mass_string = std::sqrt(msqr_string);
2912 logg[
LOutput].debug(
"The string mass (GeV) should be ", mass_string);
2916 if (std::fabs(QTrx_add_pos) <
small_number * mass_string &&
2917 std::fabs(QTry_add_pos) <
small_number * mass_string &&
2918 std::fabs(QTrx_add_neg) <
small_number * mass_string &&
2919 std::fabs(QTry_add_neg) <
small_number * mass_string) {
2920 logg[
LOutput].debug(
" no need to add transverse momenta - skipping.");
2926 for (
int ipyth = 1; ipyth < event_fragments.size(); ipyth++) {
2927 if (!event_fragments[ipyth].isFinal()) {
2932 FourVector(event_fragments[ipyth].e(), event_fragments[ipyth].px(),
2933 event_fragments[ipyth].py(), event_fragments[ipyth].pz());
2934 ptot_string_ini += p_frag;
2936 const double E_string_ini = ptot_string_ini.
x0();
2937 const double pz_string_ini = ptot_string_ini.
threevec() * evec_basis[0];
2938 const double ppos_string_ini = (E_string_ini + pz_string_ini) * M_SQRT1_2;
2939 const double pneg_string_ini = (E_string_ini - pz_string_ini) * M_SQRT1_2;
2941 const double yrapid_string_ini =
2942 0.5 * std::log(ppos_string_ini / pneg_string_ini);
2948 int ip_backward = 0;
2949 double y_forward = 0.;
2950 double y_backward = 0.;
2951 ptot_string_ini =
FourVector(0., 0., 0., 0.);
2953 for (
int ipyth = 1; ipyth < event_fragments.size(); ipyth++) {
2954 if (!event_fragments[ipyth].isFinal()) {
2959 FourVector(event_fragments[ipyth].e(), event_fragments[ipyth].px(),
2960 event_fragments[ipyth].py(), event_fragments[ipyth].pz());
2961 ptot_string_ini += p_frag;
2963 const double E_frag = p_frag.
x0();
2964 const double pl_frag = p_frag.
threevec() * evec_basis[0];
2965 double y_current = 0.5 * std::log((E_frag + pl_frag) / (E_frag - pl_frag));
2966 if (y_current > y_forward) {
2968 y_forward = y_current;
2970 if (y_current < y_backward) {
2971 ip_backward = ipyth;
2972 y_backward = y_current;
2975 logg[
LOutput].debug(
" The most forward hadron is ip_forward = ", ip_forward,
2976 " with rapidity ", y_forward);
2977 logg[
LOutput].debug(
" The most backward hadron is ip_backward = ",
2978 ip_backward,
" with rapidity ", y_backward);
2980 const double px_string_ini = ptot_string_ini.
threevec() * evec_basis[1];
2981 const double py_string_ini = ptot_string_ini.
threevec() * evec_basis[2];
2985 bool correct_px = std::fabs(px_string_ini + QTrx_add_pos + QTrx_add_neg -
2989 " input transverse momenta in x-axis are not consistent.");
2994 bool correct_py = std::fabs(py_string_ini + QTry_add_pos + QTry_add_neg -
2998 " input transverse momenta in y-axis are not consistent.");
3002 Pythia8::Vec4 pvec_string_now =
3006 " Adding transverse momentum to the most forward hadron.");
3007 pvec_string_now -= event_fragments[ip_forward].p();
3008 const double mass_frag_pos = event_fragments[ip_forward].p().mCalc();
3011 event_fragments[ip_forward].e(), event_fragments[ip_forward].px(),
3012 event_fragments[ip_forward].py(), event_fragments[ip_forward].pz());
3015 QTrx_add_pos * evec_basis[1] +
3016 QTry_add_pos * evec_basis[2];
3018 double E_new_frag_pos =
3019 std::sqrt(mom_new_frag_pos.
sqr() + mass_frag_pos * mass_frag_pos);
3020 Pythia8::Vec4 pvec_new_frag_pos =
set_Vec4(E_new_frag_pos, mom_new_frag_pos);
3021 pvec_string_now += pvec_new_frag_pos;
3023 event_fragments[ip_forward].p(pvec_new_frag_pos);
3026 " Adding transverse momentum to the most backward hadron.");
3027 pvec_string_now -= event_fragments[ip_backward].p();
3028 const double mass_frag_neg = event_fragments[ip_backward].p().mCalc();
3031 event_fragments[ip_backward].e(), event_fragments[ip_backward].px(),
3032 event_fragments[ip_backward].py(), event_fragments[ip_backward].pz());
3035 QTrx_add_neg * evec_basis[1] +
3036 QTry_add_neg * evec_basis[2];
3038 double E_new_frag_neg =
3039 std::sqrt(mom_new_frag_neg.
sqr() + mass_frag_neg * mass_frag_neg);
3040 Pythia8::Vec4 pvec_new_frag_neg =
set_Vec4(E_new_frag_neg, mom_new_frag_neg);
3041 pvec_string_now += pvec_new_frag_neg;
3043 event_fragments[ip_backward].p(pvec_new_frag_neg);
3046 event_fragments[0].p(pvec_string_now);
3047 event_fragments[0].m(pvec_string_now.mCalc());
3050 double mTrn_frag_all = 0.;
3051 for (
int ipyth = 1; ipyth < event_fragments.size(); ipyth++) {
3052 if (!event_fragments[ipyth].isFinal()) {
3057 FourVector(event_fragments[ipyth].e(), event_fragments[ipyth].px(),
3058 event_fragments[ipyth].py(), event_fragments[ipyth].pz());
3059 ptot_string_ini += p_frag;
3061 const double E_frag = p_frag.
x0();
3062 const double pl_frag = p_frag.
threevec() * evec_basis[0];
3063 const double ppos_frag = (E_frag + pl_frag) * M_SQRT1_2;
3064 const double pneg_frag = (E_frag - pl_frag) * M_SQRT1_2;
3065 const double mTrn_frag = std::sqrt(2. * ppos_frag * pneg_frag);
3066 mTrn_frag_all += mTrn_frag;
3069 "Sum of transverse masses (GeV) of all fragmented hadrons : ",
3073 if (mTrn_string < mTrn_frag_all) {
3074 logg[
LOutput].debug(
" which is larger than mT of the actual string ",
3079 double mass_string_now = pvec_string_now.mCalc();
3080 double msqr_string_now = mass_string_now * mass_string_now;
3083 FourVector(pvec_string_now.e(), pvec_string_now.px(),
3084 pvec_string_now.py(), pvec_string_now.pz());
3085 double E_string_now = p_string_now.
x0();
3086 double pz_string_now = p_string_now.
threevec() * evec_basis[0];
3087 logg[
LOutput].debug(
"The string mass (GeV) at this point : ",
3089 double ppos_string_now = (E_string_now + pz_string_now) * M_SQRT1_2;
3090 double pneg_string_now = (E_string_now - pz_string_now) * M_SQRT1_2;
3092 double yrapid_string_now = 0.5 * std::log(ppos_string_now / pneg_string_now);
3093 logg[
LOutput].debug(
"The momentum-space rapidity of string at this point : ",
3096 "The momentum-space rapidities of hadrons will be changed.");
3097 const int niter_max = 10000;
3098 bool accepted =
false;
3099 double fac_all_yrapid = 1.;
3104 for (
int iiter = 0; iiter < niter_max; iiter++) {
3105 if (std::fabs(mass_string_now - mass_string) <
really_small * mass_string) {
3109 double E_deriv = 0.;
3110 double pz_deriv = 0.;
3114 for (
int ipyth = 1; ipyth < event_fragments.size(); ipyth++) {
3115 if (!event_fragments[ipyth].isFinal()) {
3120 FourVector(event_fragments[ipyth].e(), event_fragments[ipyth].px(),
3121 event_fragments[ipyth].py(), event_fragments[ipyth].pz());
3122 const double E_frag = p_frag.
x0();
3123 const double pl_frag = p_frag.
threevec() * evec_basis[0];
3124 const double ppos_frag = (E_frag + pl_frag) * M_SQRT1_2;
3125 const double pneg_frag = (E_frag - pl_frag) * M_SQRT1_2;
3126 const double mTrn_frag = std::sqrt(2. * ppos_frag * pneg_frag);
3127 const double y_frag = 0.5 * std::log(ppos_frag / pneg_frag);
3129 E_deriv += mTrn_frag * (y_frag - yrapid_string_now) * std::sinh(y_frag);
3130 pz_deriv += mTrn_frag * (y_frag - yrapid_string_now) * std::cosh(y_frag);
3132 double slope = 2. * (E_string_now * E_deriv - pz_string_now * pz_deriv);
3133 double fac_yrapid = 1. + std::tanh((msqr_string - msqr_string_now) / slope);
3134 fac_all_yrapid *= fac_yrapid;
3138 (1. - fac_yrapid) * yrapid_string_now);
3140 pvec_string_now = event_fragments[0].p();
3141 mass_string_now = pvec_string_now.mCalc();
3142 msqr_string_now = mass_string_now * mass_string_now;
3143 p_string_now =
FourVector(pvec_string_now.e(), pvec_string_now.px(),
3144 pvec_string_now.py(), pvec_string_now.pz());
3145 E_string_now = p_string_now.
x0();
3146 pz_string_now = p_string_now.
threevec() * evec_basis[0];
3147 ppos_string_now = (E_string_now + pz_string_now) * M_SQRT1_2;
3148 pneg_string_now = (E_string_now - pz_string_now) * M_SQRT1_2;
3149 yrapid_string_now = 0.5 * std::log(ppos_string_now / pneg_string_now);
3150 logg[
LOutput].debug(
" step ", iiter + 1,
" : fac_yrapid = ", fac_yrapid,
3151 " , string mass (GeV) = ", mass_string_now,
3152 " , string rapidity = ", yrapid_string_now);
3156 logg[
LOutput].debug(
" Too many iterations in rapidity rescaling.");
3160 "The overall factor multiplied to the rapidities of hadrons = ",
3162 logg[
LOutput].debug(
"The momentum-space rapidity of string at this point : ",
3164 const double y_diff = yrapid_string - yrapid_string_now;
3165 logg[
LOutput].debug(
"The hadrons will be boosted by rapidity ", y_diff,
3166 " for the longitudinal momentum conservation.");
3175 double suppression_factor) {
3190 ParticleList &list) {
3191 assert(list.size() >= 2);
3192 int end = list.size() - 1;
3195 i1 <= end && !list[i1].pdgcode().contains_enough_valence_quarks(nq1);
3199 i2 >= 0 && !list[i2].pdgcode().contains_enough_valence_quarks(nq2);
3202 std::pair<int, int> indices(i1, i2);
3207 ParticleList &outgoing_particles,
3209 double suppression_factor) {
3212 data.set_cross_section_scaling_factor(0.0);
3215 std::sort(outgoing_particles.begin(), outgoing_particles.end(),
3217 return i.momentum().velocity() * evecLong >
3218 j.momentum().velocity() * evecLong;
3221 switch (baryon_string) {
3235 throw std::runtime_error(
"string is neither mesonic nor baryonic");
3240 std::pair<int, int> i =
find_leading(nq1, nq2, outgoing_particles);
3241 std::pair<int, int> j =
find_leading(nq2, nq1, outgoing_particles);
3242 if (baryon_string == 0 && i.second - i.first < j.second - j.first) {
3245 suppression_factor);
3249 suppression_factor);
3269 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...
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.
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 implementing 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...
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]
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