Version: SMASH-1.8
smash::StringProcess Class Reference

#include <processstring.h>

String excitation processes used in SMASH.

Only one instance of this class should be created.

This class implements string excitation processes based on the UrQMD model Bass:1998ca [4], Bleicher:1999xi [8] and subsequent fragmentation according to the LUND/PYTHIA fragmentation scheme Andersson:1983ia [2], Sjostrand:2014zea [41].

The class implements the following functionality:

  • given two colliding initial state particles it provides hadronic final state after single diffractive, double diffractive and non-diffractive string excitation
  • owns a Pythia8::SigmaTotal object to compute corresponding cross-sections
  • owns a Pythia object, that allows to fragment strings

Definition at line 47 of file processstring.h.

Collaboration diagram for smash::StringProcess:
[legend]

Public Member Functions

 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. More...
 
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. More...
 
void init_pythia_hadron_rndm ()
 Set PYTHIA random seeds to be desired values. More...
 
Pythia8::Pythia * get_ptr_pythia_parton ()
 Function to get the PYTHIA object for hard string routine. More...
 
std::array< double, 3 > cross_sections_diffractive (int pdg_a, int pdg_b, double sqrt_s)
 Interface to pythia_sigmatot_ to compute cross-sections of A+B-> different final states Schuler:1993wr [39]. More...
 
void set_pmin_gluon_lightcone (double p_light_cone_min)
 set the minimum lightcone momentum scale carried by gluon. More...
 
void set_pow_fgluon (double betapow)
 lightcone momentum fraction of gluon is sampled according to probability distribution P(x) = 1/x * (1 - x)^{1 + pow_fgluon_beta_} in double-diffractive processes. More...
 
void set_pow_fquark (double alphapow, double betapow)
 lightcone momentum fraction of quark is sampled according to probability distribution \( P(x) = x^{pow_fquark_alpha_ - 1} * (1 - x)^{pow_fquark_beta_ - 1} \) in non-diffractive processes. More...
 
void set_sigma_qperp_ (double sigma_qperp)
 set the average amount of transverse momentum transfer sigma_qperp_. More...
 
void set_tension_string (double kappa_string)
 set the string tension, which is used in append_final_state. More...
 
void init (const ParticleList &incoming, double tcoll)
 initialization feed intial particles, time of collision and gamma factor of the center of mass. More...
 
void compute_incoming_lightcone_momenta ()
 compute the lightcone momenta of incoming particles where the longitudinal direction is set to be same as that of the three-momentum of particle A. More...
 
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. More...
 
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. More...
 
bool next_SDiff (bool is_AB_to_AX)
 Single-diffractive process is based on single pomeron exchange described in Ingelman:1984ns [22]. More...
 
bool next_DDiff ()
 Double-diffractive process ( A + B -> X + X ) is similar to the single-diffractive process, but lightcone momenta of gluons are sampled in the same was as the UrQMD model Bass:1998ca [4], Bleicher:1999xi [8]. More...
 
bool next_NDiffSoft ()
 Soft Non-diffractive process is modelled in accordance with dual-topological approach Capella:1978ig [12]. More...
 
bool next_NDiffHard ()
 Hard Non-diffractive process is based on PYTHIA 8 with partonic showers and interactions. More...
 
bool next_BBbarAnn ()
 Baryon-antibaryon annihilation process Based on what UrQMD Bass:1998ca [4], Bleicher:1999xi [8] does, it create two mesonic strings after annihilating one quark-antiquark pair. More...
 
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. More...
 
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 size 5. More...
 
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 into other flavors. More...
 
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 into other flavors. More...
 
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 into the desired ones according to the excess of quarks and anti-quarks. More...
 
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 event record. More...
 
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, from a given PYTHIA event record. More...
 
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. More...
 
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. More...
 
ParticleList get_final_state ()
 a function to get the final state particle list which is called after the collision More...
 
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:1983ia [2]. More...
 
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.2 Andersson:1983ia [2], Sjostrand:2014zea [41]. More...
 
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 the consituent masses). More...
 
int get_hadrontype_from_quark (int idq1, int idq2)
 Determines hadron type from valence quark constituents. More...
 
int get_resonance_from_quark (int idq1, int idq2, double mass)
 
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 StringFragmentation::finalTwo in StringFragmentation.cc of PYTHIA 8. More...
 
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)
 
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. More...
 
double getPPosA ()
 
double getPNegA ()
 
double getPPosB ()
 
double getPnegB ()
 
double get_massA ()
 
double get_massB ()
 
double get_sqrts ()
 
std::array< PdgCode, 2 > get_PDGs ()
 
std::array< FourVector, 2 > get_plab ()
 
std::array< FourVector, 2 > get_pcom ()
 
FourVector get_ucom ()
 
ThreeVector get_vcom ()
 
double get_tcoll ()
 

Static Public Member Functions

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 More...
 
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 constituents the actual hadron has compared to the mapped one. More...
 
static bool append_intermediate_list (int pdgid, FourVector momentum, ParticleList &intermediate_particles)
 append new particle from PYTHIA to a specific particle list More...
 
static void convert_KaonLS (int &pythia_id)
 convert Kaon-L or Kaon-S into K0 or Anti-K0 More...
 
static void quarks_from_diquark (int diquark, int &q1, int &q2, int &deg_spin)
 find two quarks from a diquark. More...
 
static int diquark_from_quarks (int q1, int q2)
 Construct diquark from two quarks. More...
 
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. More...
 
static Pythia8::Vec4 set_Vec4 (double energy, const ThreeVector &mom)
 Easy setter of Pythia Vec4 from SMASH. More...
 
static FourVector reorient (Pythia8::Particle &particle, std::array< ThreeVector, 3 > &evec_basis)
 compute the four-momentum properly oriented in the lab frame. More...
 
static double sample_zLund (double a, double b, double mTrn)
 Sample lightcone momentum fraction according to the LUND fragmentation function. More...
 
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. More...
 
static std::pair< int, int > find_leading (int nq1, int nq2, ParticleList &list)
 Find the leading string fragments. More...
 
static void assign_scaling_factor (int nquark, ParticleData &data, double suppression_factor)
 Assign a cross section scaling factor to the given particle. More...
 
static int pdg_map_for_pythia (PdgCode &pdg)
 Take pdg code and map onto particle specie which can be handled by PYTHIA. More...
 

Private Attributes

double PPosA_
 forward lightcone momentum p^{+} of incoming particle A in CM-frame [GeV] More...
 
double PPosB_
 forward lightcone momentum p^{+} of incoming particle B in CM-frame [GeV] More...
 
double PNegA_
 backward lightcone momentum p^{-} of incoming particle A in CM-frame [GeV] More...
 
double PNegB_
 backward lightcone momentum p^{-} of incoming particle B in CM-frame [GeV] More...
 
double massA_
 mass of incoming particle A [GeV] More...
 
double massB_
 mass of incoming particle B [GeV] More...
 
double sqrtsAB_
 sqrt of Mandelstam variable s of collision [GeV] More...
 
std::array< PdgCode, 2 > PDGcodes_
 PdgCodes of incoming particles. More...
 
std::array< FourVector, 2 > plab_
 momenta of incoming particles in the lab frame [GeV] More...
 
std::array< FourVector, 2 > pcom_
 momenta of incoming particles in the center of mass frame [GeV] More...
 
FourVector ucomAB_
 velocity four vector of the center of mass in the lab frame More...
 
ThreeVector vcomAB_
 velocity three vector of the center of mass in the lab frame More...
 
std::array< ThreeVector, 3 > evecBasisAB_
 Orthonormal basis vectors in the center of mass frame, where the 0th one is parallel to momentum of incoming particle A. More...
 
int NpartFinal_
 total number of final state particles More...
 
std::array< int, 2 > NpartString_
 number of particles fragmented from strings More...
 
double pmin_gluon_lightcone_
 the minimum lightcone momentum scale carried by a gluon [GeV] More...
 
double pow_fgluon_beta_
 parameter \(\beta\) for the gluon distribution function \( P(x) = x^{-1} (1 - x)^{1 + \beta} \) More...
 
double pow_fquark_alpha_
 parameter \(\alpha\) for the quark distribution function \( P(x) = x^{\alpha - 1} (1 - x)^{\beta - 1} \) More...
 
double pow_fquark_beta_
 parameter \(\beta\) for the quark distribution function \( P(x) = x^{\alpha - 1} (1 - x)^{\beta - 1} \) More...
 
double sigma_qperp_
 Transverse momentum spread of the excited strings. More...
 
double stringz_a_leading_
 parameter (StringZ:aLund) for the fragmentation function of leading baryon in soft non-diffractive string processes More...
 
double stringz_b_leading_
 parameter (StringZ:bLund) for the fragmentation function of leading baryon in soft non-diffractive string processes More...
 
double stringz_a_produce_
 parameter (StringZ:aLund) for the fragmentation function of other (produced) hadrons in soft non-diffractive string processes More...
 
double stringz_b_produce_
 parameter (StringZ:bLund) for the fragmentation function of other (produced) hadrons in soft non-diffractive string processes More...
 
double kappa_tension_string_
 string tension [GeV/fm] More...
 
double additional_xsec_supp_
 additional cross-section suppression factor to take coherence effect into account. More...
 
double time_formation_const_
 constant proper time in the case of constant formation time [fm] More...
 
double soft_t_form_
 factor to be multiplied to formation times in soft strings More...
 
double time_collision_
 time of collision in the computational frame [fm] More...
 
bool mass_dependent_formation_times_
 Whether the formation time should depend on the mass of the fragment according to Andersson:1983ia [2] eq. More...
 
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. More...
 
bool separate_fragment_baryon_
 Whether to use a separate fragmentation function for leading baryons. More...
 
bool pythia_parton_initialized_ = false
 Remembers if Pythia is initialized or not. More...
 
ParticleList final_state_
 final state array which must be accessed after the collision More...
 
std::unique_ptr< Pythia8::Pythia > pythia_parton_
 PYTHIA object used in hard string routine. More...
 
std::unique_ptr< Pythia8::Pythia > pythia_hadron_
 PYTHIA object used in fragmentation. More...
 
Pythia8::SigmaTotal pythia_sigmatot_
 An object to compute cross-sections. More...
 
Pythia8::StringFlav pythia_stringflav_
 An object for the flavor selection in string fragmentation in the case of separate fragmentation function for leading baryon. More...
 
Pythia8::Event event_intermediate_
 event record for intermediate partonic state in the hard string routine More...
 

Constructor & Destructor Documentation

◆ StringProcess()

smash::StringProcess::StringProcess ( double  string_tension,
double  time_formation,
double  gluon_beta,
double  gluon_pmin,
double  quark_alpha,
double  quark_beta,
double  strange_supp,
double  diquark_supp,
double  sigma_perp,
double  stringz_a_leading,
double  stringz_b_leading,
double  stringz_a,
double  stringz_b,
double  string_sigma_T,
double  factor_t_form,
bool  mass_dependent_formation_times,
double  prob_proton_to_d_uu,
bool  separate_fragment_baryon,
double  popcorn_rate 
)

Constructor, initializes pythia.

Should only be called once.

Parameters
[in]string_tensionvalue of kappa_tension_string_ [GeV/fm]
[in]time_formationvalue of time_formation_const_ [fm]
[in]gluon_betavalue of pow_fgluon_beta_
[in]gluon_pminvalue of pmin_gluon_lightcone_
[in]quark_alphavalue of pow_fquark_alpha_
[in]quark_betavalue of pow_fquark_beta_
[in]strange_suppstrangeness suppression factor (StringFlav:probStoUD) in fragmentation
[in]diquark_suppdiquark suppression factor (StringFlav:probQQtoQ) in fragmentation
[in]sigma_perpvalue of sigma_qperp_ [GeV]
[in]stringz_a_leadingParameter a in Lund fragmentation function for leading baryons.
[in]stringz_b_leadingParameter b in Lund fragmentation function for leading baryons.
[in]stringz_aparameter (StringZ:aLund) for the fragmentation function
[in]stringz_bparameter (StringZ:bLund) for the fragmentation function [GeV^-2]
[in]string_sigma_Ttransverse momentum spread (StringPT:sigma) in fragmentation [GeV]
[in]factor_t_formto be multiplied to soft string formation times
[in]mass_dependent_formation_timesWhether the formation times of string fragments should depend on their mass.
[in]prob_proton_to_d_uuProbability of a nucleon to be split into the quark it contains once and a diquark another flavour.
[in]separate_fragment_baryonwhether to use a separate fragmentation function for leading baryons in non-diffractive string processes.
[in]popcorn_rateparameter (StringFlav:popcornRate) to determine the production rate of popcorn mesons from the diquark end of a string.
See also
StringProcess::common_setup_pythia(Pythia8::Pythia *, double, double, double, double, double)
pythia8235/share/Pythia8/xmldoc/FlavourSelection.xml
pythia8235/share/Pythia8/xmldoc/Fragmentation.xml
pythia8235/share/Pythia8/xmldoc/MasterSwitches.xml
pythia8235/share/Pythia8/xmldoc/MultipartonInteractions.xml

Definition at line 21 of file processstring.cc.

29  : pmin_gluon_lightcone_(gluon_pmin),
30  pow_fgluon_beta_(gluon_beta),
31  pow_fquark_alpha_(quark_alpha),
32  pow_fquark_beta_(quark_beta),
33  sigma_qperp_(sigma_perp),
34  stringz_a_leading_(stringz_a_leading),
35  stringz_b_leading_(stringz_b_leading),
36  stringz_a_produce_(stringz_a),
37  stringz_b_produce_(stringz_b),
38  kappa_tension_string_(string_tension),
40  time_formation_const_(time_formation),
41  soft_t_form_(factor_t_form),
42  time_collision_(0.),
43  mass_dependent_formation_times_(mass_dependent_formation_times),
44  prob_proton_to_d_uu_(prob_proton_to_d_uu),
45  separate_fragment_baryon_(separate_fragment_baryon) {
46  // setup and initialize pythia for hard string process
47  pythia_parton_ = make_unique<Pythia8::Pythia>(PYTHIA_XML_DIR, false);
48  /* select only non-diffractive events
49  * diffractive ones are implemented in a separate routine */
50  pythia_parton_->readString("SoftQCD:nonDiffractive = on");
51  pythia_parton_->readString("MultipartonInteractions:pTmin = 1.5");
52  pythia_parton_->readString("HadronLevel:all = off");
53  common_setup_pythia(pythia_parton_.get(), strange_supp, diquark_supp,
54  popcorn_rate, stringz_a, stringz_b, string_sigma_T);
55 
56  // setup and initialize pythia for fragmentation
57  pythia_hadron_ = make_unique<Pythia8::Pythia>(PYTHIA_XML_DIR, false);
58  /* turn off all parton-level processes to implement only hadronization */
59  pythia_hadron_->readString("ProcessLevel:all = off");
60  common_setup_pythia(pythia_hadron_.get(), strange_supp, diquark_supp,
61  popcorn_rate, stringz_a, stringz_b, string_sigma_T);
62 
63  /* initialize PYTHIA */
64  pythia_hadron_->init();
65  pythia_sigmatot_.init(&pythia_hadron_->info, pythia_hadron_->settings,
66  &pythia_hadron_->particleData, &pythia_hadron_->rndm);
67  pythia_stringflav_.init(pythia_hadron_->settings,
68  &pythia_hadron_->particleData, &pythia_hadron_->rndm,
69  &pythia_hadron_->info);
70  event_intermediate_.init("intermediate partons",
71  &pythia_hadron_->particleData);
72 
73  for (int imu = 0; imu < 3; imu++) {
74  evecBasisAB_[imu] = ThreeVector(0., 0., 0.);
75  }
76 
77  final_state_.clear();
78 }
Here is the call graph for this function:

Member Function Documentation

◆ common_setup_pythia()

void smash::StringProcess::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.

Parameters
[out]pythia_inpointer to the PYTHIA object
[in]strange_suppstrangeness suppression factor (StringFlav:probStoUD) in fragmentation
[in]diquark_suppdiquark suppression factor (StringFlav:probQQtoQ) in fragmentation
[in]popcorn_rateparameter (StringFlav:popcornRate) to determine the production rate of popcorn mesons from the diquark end of a string.
[in]stringz_aparameter (StringZ:aLund) for the fragmentation function
[in]stringz_bparameter (StringZ:bLund) for the fragmentation function
[in]string_sigma_Ttransverse momentum spread (StringPT:sigma) in fragmentation [GeV]
See also
pythia8235/share/Pythia8/xmldoc/FlavourSelection.xml
pythia8235/share/Pythia8/xmldoc/Fragmentation.xml

Definition at line 80 of file processstring.cc.

85  {
86  // choose parametrization for mass-dependent width
87  pythia_in->readString("ParticleData:modeBreitWigner = 4");
88  /* choose minimum transverse momentum scale
89  * involved in partonic interactions */
90  pythia_in->readString("MultipartonInteractions:pTmin = 1.5");
91  pythia_in->readString("MultipartonInteractions:nSample = 10000");
92  // transverse momentum spread in string fragmentation
93  pythia_in->readString("StringPT:sigma = " + std::to_string(string_sigma_T));
94  // diquark suppression factor in string fragmentation
95  pythia_in->readString("StringFlav:probQQtoQ = " +
96  std::to_string(diquark_supp));
97  // strangeness suppression factor in string fragmentation
98  pythia_in->readString("StringFlav:probStoUD = " +
99  std::to_string(strange_supp));
100  pythia_in->readString("StringFlav:popcornRate = " +
101  std::to_string(popcorn_rate));
102  // parameters for the fragmentation function
103  pythia_in->readString("StringZ:aLund = " + std::to_string(stringz_a));
104  pythia_in->readString("StringZ:bLund = " + std::to_string(stringz_b));
105 
106  // manually set the parton distribution function
107  pythia_in->readString("PDF:pSet = 13");
108  pythia_in->readString("PDF:pSetB = 13");
109  pythia_in->readString("PDF:piSet = 1");
110  pythia_in->readString("PDF:piSetB = 1");
111  pythia_in->readString("Beams:idA = 2212");
112  pythia_in->readString("Beams:idB = 2212");
113  pythia_in->readString("Beams:eCM = 10.");
114 
115  // set PYTHIA random seed from outside
116  pythia_in->readString("Random:setSeed = on");
117  // suppress unnecessary output
118  pythia_in->readString("Print:quiet = on");
119  // No resonance decays, since the resonances will be handled by SMASH
120  pythia_in->readString("HadronLevel:Decay = off");
121  // set particle masses and widths in PYTHIA to be same with those in SMASH
122  for (auto &ptype : ParticleType::list_all()) {
123  int pdgid = ptype.pdgcode().get_decimal();
124  double mass_pole = ptype.mass();
125  double width_pole = ptype.width_at_pole();
126  // check if the particle species is in PYTHIA
127  if (pythia_in->particleData.isParticle(pdgid)) {
128  // set mass and width in PYTHIA
129  pythia_in->particleData.m0(pdgid, mass_pole);
130  pythia_in->particleData.mWidth(pdgid, width_pole);
131  } else if (pdgid == 310 || pdgid == 130) {
132  // set mass and width of Kaon-L and Kaon-S
133  pythia_in->particleData.m0(pdgid, kaon_mass);
134  pythia_in->particleData.mWidth(pdgid, 0.);
135  }
136  }
137 
138  // make energy-momentum conservation in PYTHIA more precise
139  pythia_in->readString("Check:epTolErr = 1e-6");
140  pythia_in->readString("Check:epTolWarn = 1e-8");
141 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ init_pythia_hadron_rndm()

void smash::StringProcess::init_pythia_hadron_rndm ( )
inline

Set PYTHIA random seeds to be desired values.

The value is recalculated such that it is allowed by PYTHIA.

See also
smash::maximum_rndm_seed_in_pythia

Definition at line 277 of file processstring.h.

277  {
278  const int seed_new =
280 
281  pythia_hadron_->rndm.init(seed_new);
282  logg[LPythia].debug("pythia_hadron_ : rndm is initialized with seed ", seed_new);
283  }
Here is the call graph for this function:

◆ get_ptr_pythia_parton()

Pythia8::Pythia* smash::StringProcess::get_ptr_pythia_parton ( )
inline

Function to get the PYTHIA object for hard string routine.

Returns
pointer to the PYTHIA object used in hard string routine

Definition at line 291 of file processstring.h.

291 { return pythia_parton_.get(); }

◆ cross_sections_diffractive()

std::array<double, 3> smash::StringProcess::cross_sections_diffractive ( int  pdg_a,
int  pdg_b,
double  sqrt_s 
)
inline

Interface to pythia_sigmatot_ to compute cross-sections of A+B-> different final states Schuler:1993wr [39].

Parameters
[in]pdg_apdg code of incoming particle A
[in]pdg_bpdg code of incoming particle B
[in]sqrt_scollision energy in the center of mass frame [GeV]
Returns
array with single diffractive cross-sections AB->AX, AB->XB and double diffractive AB->XX.

Definition at line 302 of file processstring.h.

303  {
304  // This threshold magic is following Pythia. Todo(ryu): take care of this.
305  double sqrts_threshold = 2. * (1. + 1.0e-6);
306  /* In the case of mesons, the corresponding vector meson masses
307  * are used to evaluate the energy threshold. */
308  const int pdg_a_mod =
309  (std::abs(pdg_a) > 1000) ? pdg_a : 10 * (std::abs(pdg_a) / 10) + 3;
310  const int pdg_b_mod =
311  (std::abs(pdg_b) > 1000) ? pdg_b : 10 * (std::abs(pdg_b) / 10) + 3;
312  sqrts_threshold += pythia_hadron_->particleData.m0(pdg_a_mod) +
313  pythia_hadron_->particleData.m0(pdg_b_mod);
314  /* Constant cross-section for sub-processes below threshold equal to
315  * cross-section at the threshold. */
316  if (sqrt_s < sqrts_threshold) {
317  sqrt_s = sqrts_threshold;
318  }
319  pythia_sigmatot_.calc(pdg_a, pdg_b, sqrt_s);
320  return {pythia_sigmatot_.sigmaAX(), pythia_sigmatot_.sigmaXB(),
321  pythia_sigmatot_.sigmaXX()};
322  }
Here is the caller graph for this function:

◆ set_pmin_gluon_lightcone()

void smash::StringProcess::set_pmin_gluon_lightcone ( double  p_light_cone_min)
inline

set the minimum lightcone momentum scale carried by gluon.

Todo:
The following set_ functions are replaced with constructor with arguments.

Must be cleaned up if necessary. This is relevant for the double-diffractive process. The minimum lightcone momentum fraction is set to be pmin_gluon_lightcone_/sqrtsAB.

Parameters
p_light_cone_mina value that we want to use for pmin_gluon_lightcone_.

Definition at line 338 of file processstring.h.

338  {
339  pmin_gluon_lightcone_ = p_light_cone_min;
340  }

◆ set_pow_fgluon()

void smash::StringProcess::set_pow_fgluon ( double  betapow)
inline

lightcone momentum fraction of gluon is sampled according to probability distribution P(x) = 1/x * (1 - x)^{1 + pow_fgluon_beta_} in double-diffractive processes.

Parameters
betapowis a value that we want to use for pow_fgluon_beta_.

Definition at line 348 of file processstring.h.

348 { pow_fgluon_beta_ = betapow; }

◆ set_pow_fquark()

void smash::StringProcess::set_pow_fquark ( double  alphapow,
double  betapow 
)
inline

lightcone momentum fraction of quark is sampled according to probability distribution \( P(x) = x^{pow_fquark_alpha_ - 1} * (1 - x)^{pow_fquark_beta_ - 1} \) in non-diffractive processes.

Parameters
alphapowis a value that we want to use for pow_fquark_alpha_.
betapowis a value that we want to use for pow_fquark_beta_.

Definition at line 357 of file processstring.h.

357  {
358  pow_fquark_alpha_ = alphapow;
359  pow_fquark_beta_ = betapow;
360  }

◆ set_sigma_qperp_()

void smash::StringProcess::set_sigma_qperp_ ( double  sigma_qperp)
inline

set the average amount of transverse momentum transfer sigma_qperp_.

Parameters
sigma_qperpis a value that we want to use for sigma_qperp_.

Definition at line 365 of file processstring.h.

365 { sigma_qperp_ = sigma_qperp; }

◆ set_tension_string()

void smash::StringProcess::set_tension_string ( double  kappa_string)
inline

set the string tension, which is used in append_final_state.

Parameters
kappa_stringis a value that we want to use for string tension.

Definition at line 370 of file processstring.h.

370  {
371  kappa_tension_string_ = kappa_string;
372  }

◆ init()

void smash::StringProcess::init ( const ParticleList &  incoming,
double  tcoll 
)

initialization feed intial particles, time of collision and gamma factor of the center of mass.

Parameters
[in]incomingis the list of initial state particles.
[in]tcollis time of collision.

Definition at line 200 of file processstring.cc.

200  {
201  PDGcodes_[0] = incoming[0].pdgcode();
202  PDGcodes_[1] = incoming[1].pdgcode();
203  massA_ = incoming[0].effective_mass();
204  massB_ = incoming[1].effective_mass();
205 
206  plab_[0] = incoming[0].momentum();
207  plab_[1] = incoming[1].momentum();
208 
209  // compute sqrts and velocity of the center of mass.
210  sqrtsAB_ = (plab_[0] + plab_[1]).abs();
211  ucomAB_ = (plab_[0] + plab_[1]) / sqrtsAB_;
213 
214  pcom_[0] = plab_[0].lorentz_boost(vcomAB_);
215  pcom_[1] = plab_[1].lorentz_boost(vcomAB_);
216 
217  const double pabscomAB = pCM(sqrtsAB_, massA_, massB_);
218  ThreeVector evec_coll = pcom_[0].threevec() / pabscomAB;
220 
222 
223  time_collision_ = tcoll;
224 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ make_orthonormal_basis()

void smash::StringProcess::make_orthonormal_basis ( ThreeVector evec_polar,
std::array< ThreeVector, 3 > &  evec_basis 
)
static

compute three orthonormal basis vectors from unit vector in the longitudinal direction

Parameters
[in]evec_polarunit three-vector in the longitudinal direction
[out]evec_basisorthonormal basis vectors of which evec_basis[0] is in the longitudinal direction while evec_basis[1] and evec_basis[2] span the transverse plane.

Definition at line 1615 of file processstring.cc.

1616  {
1617  assert(std::fabs(evec_polar.sqr() - 1.) < really_small);
1618 
1619  if (std::abs(evec_polar.x3()) < (1. - 1.0e-8)) {
1620  double ex, ey, et;
1621  double theta, phi;
1622 
1623  // evec_basis[0] is set to be longitudinal direction
1624  evec_basis[0] = evec_polar;
1625 
1626  theta = std::acos(evec_basis[0].x3());
1627 
1628  ex = evec_basis[0].x1();
1629  ey = evec_basis[0].x2();
1630  et = std::sqrt(ex * ex + ey * ey);
1631  if (ey > 0.) {
1632  phi = std::acos(ex / et);
1633  } else {
1634  phi = -std::acos(ex / et);
1635  }
1636 
1637  /* The transverse plane is spanned
1638  * by evec_basis[1] and evec_basis[2]. */
1639  evec_basis[1].set_x1(std::cos(theta) * std::cos(phi));
1640  evec_basis[1].set_x2(std::cos(theta) * std::sin(phi));
1641  evec_basis[1].set_x3(-std::sin(theta));
1642 
1643  evec_basis[2].set_x1(-std::sin(phi));
1644  evec_basis[2].set_x2(std::cos(phi));
1645  evec_basis[2].set_x3(0.);
1646  } else {
1647  // if evec_polar is very close to the z axis
1648  if (evec_polar.x3() > 0.) {
1649  evec_basis[1] = ThreeVector(1., 0., 0.);
1650  evec_basis[2] = ThreeVector(0., 1., 0.);
1651  evec_basis[0] = ThreeVector(0., 0., 1.);
1652  } else {
1653  evec_basis[1] = ThreeVector(0., 1., 0.);
1654  evec_basis[2] = ThreeVector(1., 0., 0.);
1655  evec_basis[0] = ThreeVector(0., 0., -1.);
1656  }
1657  }
1658 
1659  assert(std::fabs(evec_basis[1] * evec_basis[2]) < really_small);
1660  assert(std::fabs(evec_basis[2] * evec_basis[0]) < really_small);
1661  assert(std::fabs(evec_basis[0] * evec_basis[1]) < really_small);
1662 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ compute_incoming_lightcone_momenta()

void smash::StringProcess::compute_incoming_lightcone_momenta ( )

compute the lightcone momenta of incoming particles where the longitudinal direction is set to be same as that of the three-momentum of particle A.

Definition at line 1664 of file processstring.cc.

1664  {
1665  PPosA_ = (pcom_[0].x0() + evecBasisAB_[0] * pcom_[0].threevec()) * M_SQRT1_2;
1666  PNegA_ = (pcom_[0].x0() - evecBasisAB_[0] * pcom_[0].threevec()) * M_SQRT1_2;
1667  PPosB_ = (pcom_[1].x0() + evecBasisAB_[0] * pcom_[1].threevec()) * M_SQRT1_2;
1668  PNegB_ = (pcom_[1].x0() - evecBasisAB_[0] * pcom_[1].threevec()) * M_SQRT1_2;
1669 }
Here is the caller graph for this function:

◆ set_mass_and_direction_2strings()

bool smash::StringProcess::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.

Parameters
[in]quarkspdg ids of string ends
[in]pstr_com4-momenta of strings in the C.o.m. frame [GeV]
[out]m_strmasses of strings [GeV]
[out]evec_strare directions in which strings are stretched.
Returns
whether masses are above the threshold

Definition at line 311 of file processstring.cc.

314  {
315  std::array<bool, 2> found_mass;
316  for (int i = 0; i < 2; i++) {
317  found_mass[i] = false;
318 
319  m_str[i] = pstr_com[i].sqr();
320  m_str[i] = (m_str[i] > 0.) ? std::sqrt(m_str[i]) : 0.;
321  const double threshold = pythia_hadron_->particleData.m0(quarks[i][0]) +
322  pythia_hadron_->particleData.m0(quarks[i][1]);
323  // string mass must be larger than threshold set by PYTHIA.
324  if (m_str[i] > threshold) {
325  found_mass[i] = true;
326  /* Determine direction in which string i is stretched.
327  * This is set to be same with the collision axis
328  * in the center of mass frame.
329  * Initial state partons inside incoming hadrons are
330  * moving along the collision axis,
331  * which is parallel to three momenta of incoming hadrons
332  * in the center of mass frame.
333  * Given that partons are assumed to be massless,
334  * their four momenta are null vectors and parallel to pnull.
335  * If we take unit three-vector of prs,
336  * which is pnull in the rest frame of string,
337  * it would be the direction in which string ends are moving. */
338  const ThreeVector mom = pcom_[i].threevec();
339  const FourVector pnull(mom.abs(), mom);
340  const FourVector prs = pnull.lorentz_boost(pstr_com[i].velocity());
341  evec_str[i] = prs.threevec() / prs.threevec().abs();
342  }
343  }
344 
345  return found_mass[0] && found_mass[1];
346 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ make_final_state_2strings()

bool smash::StringProcess::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.

Parameters
[in]quarkspdg ids of string ends
[in]pstr_com4-momenta of strings in the C.o.m. frame [GeV]
[in]m_strmasses of strings [GeV]
[out]evec_strare directions in which strings are stretched.
[in]flip_string_endsis whether or not we randomly switch string ends.
[in]separate_fragment_baryonis whether to fragment leading baryons (or anti-baryons) with a separate fragmentation function.
Returns
whether fragmentations and final state creation was successful

Definition at line 348 of file processstring.cc.

353  {
354  const std::array<FourVector, 2> ustr_com = {pstr_com[0] / m_str[0],
355  pstr_com[1] / m_str[1]};
356  for (int i = 0; i < 2; i++) {
357  ParticleList new_intermediate_particles;
358 
359  // determine direction in which string i is stretched.
360  ThreeVector evec = evec_str[i];
361  // perform fragmentation and add particles to final_state.
362  int nfrag = fragment_string(quarks[i][0], quarks[i][1], m_str[i], evec,
363  flip_string_ends, separate_fragment_baryon,
364  new_intermediate_particles);
365  if (nfrag <= 0) {
366  NpartString_[i] = 0;
367  return false;
368  }
369  NpartString_[i] =
370  append_final_state(new_intermediate_particles, ustr_com[i], evec);
371  assert(nfrag == NpartString_[i]);
372  }
373  if ((NpartString_[0] > 0) && (NpartString_[1] > 0)) {
375  return true;
376  }
377  return false;
378 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ next_SDiff()

bool smash::StringProcess::next_SDiff ( bool  is_AB_to_AX)

Single-diffractive process is based on single pomeron exchange described in Ingelman:1984ns [22].

Parameters
[in]is_AB_to_AXspecifies which hadron to excite into a string. true : A + B -> A + X, false : A + B -> X + B
Returns
whether the process is successfully implemented.

Definition at line 229 of file processstring.cc.

229  {
230  NpartFinal_ = 0;
231  NpartString_[0] = 0;
232  NpartString_[1] = 0;
233  final_state_.clear();
234 
235  double massH = is_AB_to_AX ? massA_ : massB_;
236  double mstrMin = is_AB_to_AX ? massB_ : massA_;
237  double mstrMax = sqrtsAB_ - massH;
238 
239  int idqX1, idqX2;
240  double QTrn, QTrx, QTry;
241  double pabscomHX_sqr, massX;
242 
243  // decompose hadron into quarks
244  make_string_ends(is_AB_to_AX ? PDGcodes_[1] : PDGcodes_[0], idqX1, idqX2,
246  // string mass must be larger than threshold set by PYTHIA.
247  mstrMin = pythia_hadron_->particleData.m0(idqX1) +
248  pythia_hadron_->particleData.m0(idqX2);
249  // this threshold cannot be larger than maximum of allowed string mass.
250  if (mstrMin > mstrMax) {
251  return false;
252  }
253  // sample the transverse momentum transfer
254  QTrx = random::normal(0., sigma_qperp_ * M_SQRT1_2);
255  QTry = random::normal(0., sigma_qperp_ * M_SQRT1_2);
256  QTrn = std::sqrt(QTrx * QTrx + QTry * QTry);
257  /* sample the string mass and
258  * evaluate the three-momenta of hadron and string. */
259  massX = random::power(-1.0, mstrMin, mstrMax);
260  pabscomHX_sqr = pCM_sqr(sqrtsAB_, massH, massX);
261  /* magnitude of the three momentum must be larger
262  * than the transverse momentum. */
263  const bool foundPabsX = pabscomHX_sqr > QTrn * QTrn;
264 
265  if (!foundPabsX) {
266  return false;
267  }
268  double sign_direction = is_AB_to_AX ? 1. : -1.;
269  // determine three momentum of the final state hadron
270  const ThreeVector cm_momentum =
271  sign_direction *
272  (evecBasisAB_[0] * std::sqrt(pabscomHX_sqr - QTrn * QTrn) +
273  evecBasisAB_[1] * QTrx + evecBasisAB_[2] * QTry);
274  const FourVector pstrHcom(std::sqrt(pabscomHX_sqr + massH * massH),
275  cm_momentum);
276  const FourVector pstrXcom(std::sqrt(pabscomHX_sqr + massX * massX),
277  -cm_momentum);
278 
279  const FourVector ustrXcom = pstrXcom / massX;
280  /* determine direction in which the string is stretched.
281  * this is set to be same with the the collision axis
282  * in the center of mass frame. */
283  const ThreeVector threeMomentum =
284  is_AB_to_AX ? pcom_[1].threevec() : pcom_[0].threevec();
285  const FourVector pnull = FourVector(threeMomentum.abs(), threeMomentum);
286  const FourVector prs = pnull.lorentz_boost(ustrXcom.velocity());
287  ThreeVector evec = prs.threevec() / prs.threevec().abs();
288  // perform fragmentation and add particles to final_state.
289  ParticleList new_intermediate_particles;
290  int nfrag = fragment_string(idqX1, idqX2, massX, evec, true, false,
291  new_intermediate_particles);
292  if (nfrag < 1) {
293  NpartString_[0] = 0;
294  return false;
295  }
296  NpartString_[0] =
297  append_final_state(new_intermediate_particles, ustrXcom, evec);
298 
299  NpartString_[1] = 1;
300  PdgCode hadron_code = is_AB_to_AX ? PDGcodes_[0] : PDGcodes_[1];
301  ParticleData new_particle(ParticleType::find(hadron_code));
302  new_particle.set_4momentum(pstrHcom);
303  new_particle.set_cross_section_scaling_factor(1.);
304  new_particle.set_formation_time(time_collision_);
305  final_state_.push_back(new_particle);
306 
308  return true;
309 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ next_DDiff()

bool smash::StringProcess::next_DDiff ( )

Double-diffractive process ( A + B -> X + X ) is similar to the single-diffractive process, but lightcone momenta of gluons are sampled in the same was as the UrQMD model Bass:1998ca [4], Bleicher:1999xi [8].

String masses are computed after pomeron exchange aquiring transverse momentum transfer.

Returns
whether the process is successfully implemented.

Definition at line 381 of file processstring.cc.

381  {
382  NpartFinal_ = 0;
383  NpartString_[0] = 0;
384  NpartString_[1] = 0;
385  final_state_.clear();
386 
387  std::array<std::array<int, 2>, 2> quarks;
388  std::array<FourVector, 2> pstr_com;
389  std::array<double, 2> m_str;
390  std::array<ThreeVector, 2> evec_str;
391  ThreeVector threeMomentum;
392 
393  // decompose hadron into quark (and diquark) contents
394  make_string_ends(PDGcodes_[0], quarks[0][0], quarks[0][1],
396  make_string_ends(PDGcodes_[1], quarks[1][0], quarks[1][1],
398  // sample the lightcone momentum fraction carried by gluons
399  const double xmin_gluon_fraction = pmin_gluon_lightcone_ / sqrtsAB_;
400  const double xfracA =
401  random::beta_a0(xmin_gluon_fraction, pow_fgluon_beta_ + 1.);
402  const double xfracB =
403  random::beta_a0(xmin_gluon_fraction, pow_fgluon_beta_ + 1.);
404  // sample the transverse momentum transfer
405  const double QTrx = random::normal(0., sigma_qperp_ * M_SQRT1_2);
406  const double QTry = random::normal(0., sigma_qperp_ * M_SQRT1_2);
407  const double QTrn = std::sqrt(QTrx * QTrx + QTry * QTry);
408  // evaluate the lightcone momentum transfer
409  const double QPos = -QTrn * QTrn / (2. * xfracB * PNegB_);
410  const double QNeg = QTrn * QTrn / (2. * xfracA * PPosA_);
411  // compute four-momentum of string 1
412  threeMomentum =
413  evecBasisAB_[0] * (PPosA_ + QPos - PNegA_ - QNeg) * M_SQRT1_2 +
414  evecBasisAB_[1] * QTrx + evecBasisAB_[2] * QTry;
415  pstr_com[0] =
416  FourVector((PPosA_ + QPos + PNegA_ + QNeg) * M_SQRT1_2, threeMomentum);
417  // compute four-momentum of string 2
418  threeMomentum =
419  evecBasisAB_[0] * (PPosB_ - QPos - PNegB_ + QNeg) * M_SQRT1_2 -
420  evecBasisAB_[1] * QTrx - evecBasisAB_[2] * QTry;
421  pstr_com[1] =
422  FourVector((PPosB_ - QPos + PNegB_ - QNeg) * M_SQRT1_2, threeMomentum);
423 
424  const bool found_masses =
425  set_mass_and_direction_2strings(quarks, pstr_com, m_str, evec_str);
426  if (!found_masses) {
427  return false;
428  }
429  const bool flip_string_ends = true;
430  const bool success = make_final_state_2strings(
431  quarks, pstr_com, m_str, evec_str, flip_string_ends, false);
432  return success;
433 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ next_NDiffSoft()

bool smash::StringProcess::next_NDiffSoft ( )

Soft Non-diffractive process is modelled in accordance with dual-topological approach Capella:1978ig [12].

This involves a parton exchange in conjunction with momentum transfer. Probability distribution function of the lightcone momentum fraction carried by quark is based on the UrQMD model Bass:1998ca [4], Bleicher:1999xi [8].

Returns
whether the process is successfully implemented.
Exceptions
std::runtime_errorif incoming particles are neither mesonic nor baryonic

Definition at line 436 of file processstring.cc.

436  {
437  NpartFinal_ = 0;
438  NpartString_[0] = 0;
439  NpartString_[1] = 0;
440  final_state_.clear();
441 
442  std::array<std::array<int, 2>, 2> quarks;
443  std::array<FourVector, 2> pstr_com;
444  std::array<double, 2> m_str;
445  std::array<ThreeVector, 2> evec_str;
446 
447  // decompose hadron into quark (and diquark) contents
448  int idqA1, idqA2, idqB1, idqB2;
451 
452  const int bar_a = PDGcodes_[0].baryon_number(),
453  bar_b = PDGcodes_[1].baryon_number();
454  if (bar_a == 1 || // baryon-baryon, baryon-meson, baryon-antibaryon
455  (bar_a == 0 && bar_b == 1) || // meson-baryon
456  (bar_a == 0 && bar_b == 0)) { // meson-meson
457  quarks[0][0] = idqB1;
458  quarks[0][1] = idqA2;
459  quarks[1][0] = idqA1;
460  quarks[1][1] = idqB2;
461  } else if (((bar_a == 0) && (bar_b == -1)) || // meson-antibaryon
462  (bar_a == -1)) { // antibaryon-baryon, antibaryon-meson,
463  // antibaryon-antibaryon
464  quarks[0][0] = idqA1;
465  quarks[0][1] = idqB2;
466  quarks[1][0] = idqB1;
467  quarks[1][1] = idqA2;
468  } else {
469  std::stringstream ss;
470  ss << " StringProcess::next_NDiff : baryonA = " << bar_a
471  << ", baryonB = " << bar_b;
472  throw std::runtime_error(ss.str());
473  }
474  // sample the lightcone momentum fraction carried by quarks
475  const double xfracA = random::beta(pow_fquark_alpha_, pow_fquark_beta_);
476  const double xfracB = random::beta(pow_fquark_alpha_, pow_fquark_beta_);
477  // sample the transverse momentum transfer
478  const double QTrx = random::normal(0., sigma_qperp_ * M_SQRT1_2);
479  const double QTry = random::normal(0., sigma_qperp_ * M_SQRT1_2);
480  const double QTrn = std::sqrt(QTrx * QTrx + QTry * QTry);
481  // evaluate the lightcone momentum transfer
482  const double QPos = -QTrn * QTrn / (2. * xfracB * PNegB_);
483  const double QNeg = QTrn * QTrn / (2. * xfracA * PPosA_);
484  const double dPPos = -xfracA * PPosA_ - QPos;
485  const double dPNeg = xfracB * PNegB_ - QNeg;
486  // compute four-momentum of string 1
487  ThreeVector threeMomentum =
488  evecBasisAB_[0] * (PPosA_ + dPPos - PNegA_ - dPNeg) * M_SQRT1_2 +
489  evecBasisAB_[1] * QTrx + evecBasisAB_[2] * QTry;
490  pstr_com[0] =
491  FourVector((PPosA_ + dPPos + PNegA_ + dPNeg) * M_SQRT1_2, threeMomentum);
492  m_str[0] = pstr_com[0].sqr();
493  // compute four-momentum of string 2
494  threeMomentum =
495  evecBasisAB_[0] * (PPosB_ - dPPos - PNegB_ + dPNeg) * M_SQRT1_2 -
496  evecBasisAB_[1] * QTrx - evecBasisAB_[2] * QTry;
497  pstr_com[1] =
498  FourVector((PPosB_ - dPPos + PNegB_ - dPNeg) * M_SQRT1_2, threeMomentum);
499 
500  const bool found_masses =
501  set_mass_and_direction_2strings(quarks, pstr_com, m_str, evec_str);
502  if (!found_masses) {
503  return false;
504  }
505  const bool flip_string_ends = false;
506  const bool success =
507  make_final_state_2strings(quarks, pstr_com, m_str, evec_str,
508  flip_string_ends, separate_fragment_baryon_);
509  return success;
510 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ next_NDiffHard()

bool smash::StringProcess::next_NDiffHard ( )

Hard Non-diffractive process is based on PYTHIA 8 with partonic showers and interactions.

Returns
whether the process is successfully implemented.

Definition at line 513 of file processstring.cc.

513  {
514  NpartFinal_ = 0;
515  final_state_.clear();
516 
517  logg[LPythia].debug("Hard non-diff. with ", PDGcodes_[0], " + ", PDGcodes_[1],
518  " at CM energy [GeV] ", sqrtsAB_);
519 
520  std::array<int, 2> pdg_for_pythia;
521  std::array<std::array<int, 5>, 2> excess_quark;
522  std::array<std::array<int, 5>, 2> excess_antiq;
523  for (int i = 0; i < 2; i++) {
524  for (int j = 0; j < 5; j++) {
525  excess_quark[i][j] = 0;
526  excess_antiq[i][j] = 0;
527  }
528 
529  // get PDG id used in PYTHIA event generation
530  pdg_for_pythia[i] = pdg_map_for_pythia(PDGcodes_[i]);
531  logg[LPythia].debug(" incoming particle ", i, " : ", PDGcodes_[i],
532  " is mapped onto ", pdg_for_pythia[i]);
533 
534  PdgCode pdgcode_for_pythia(std::to_string(pdg_for_pythia[i]));
535  /* evaluate how many more constituents incoming hadron has
536  * compared to the mapped one. */
537  find_excess_constituent(PDGcodes_[i], pdgcode_for_pythia, excess_quark[i],
538  excess_antiq[i]);
539  logg[LPythia].debug(" excess_quark[", i, "] = (", excess_quark[i][0],
540  ", ", excess_quark[i][1], ", ", excess_quark[i][2],
541  ", ", excess_quark[i][3], ", ", excess_quark[i][4],
542  ")");
543  logg[LPythia].debug(" excess_antiq[", i, "] = (", excess_antiq[i][0],
544  ", ", excess_antiq[i][1], ", ", excess_antiq[i][2],
545  ", ", excess_antiq[i][3], ", ", excess_antiq[i][4],
546  ")");
547  }
548 
549  int previous_idA = pythia_parton_->mode("Beams:idA"),
550  previous_idB = pythia_parton_->mode("Beams:idB");
551  double previous_eCM = pythia_parton_->parm("Beams:eCM");
552  // check if the initial state for PYTHIA remains same.
553  bool same_initial_state = previous_idA == pdg_for_pythia[0] &&
554  previous_idB == pdg_for_pythia[1] &&
555  std::abs(previous_eCM - sqrtsAB_) < really_small;
556 
557  /* Perform PYTHIA initialization if it was not previously initialized
558  * or the initial state changed. */
559  if (!pythia_parton_initialized_ || !same_initial_state) {
560  pythia_parton_->settings.mode("Beams:idA", pdg_for_pythia[0]);
561  pythia_parton_->settings.mode("Beams:idB", pdg_for_pythia[1]);
562  pythia_parton_->settings.parm("Beams:eCM", sqrtsAB_);
563 
565  logg[LPythia].debug("Pythia initialized with ", pdg_for_pythia[0], " + ",
566  pdg_for_pythia[1], " at CM energy [GeV] ", sqrtsAB_);
568  throw std::runtime_error("Pythia failed to initialize.");
569  }
570  }
571  /* Set the random seed of the Pythia random Number Generator.
572  * Pythia's random is controlled by SMASH in every single collision.
573  * In this way we ensure that the results are reproducible
574  * for every event if one knows SMASH random seed. */
575  const int seed_new = random::uniform_int(1, maximum_rndm_seed_in_pythia);
576  pythia_parton_->rndm.init(seed_new);
577  logg[LPythia].debug("pythia_parton_ : rndm is initialized with seed ",
578  seed_new);
579 
580  // Short notation for Pythia event
581  Pythia8::Event &event_hadron = pythia_hadron_->event;
582  logg[LPythia].debug("Pythia hard event created");
583  bool final_state_success = pythia_parton_->next();
584  logg[LPythia].debug("Pythia final state computed, success = ",
585  final_state_success);
586  if (!final_state_success) {
587  return false;
588  }
589 
590  ParticleList new_intermediate_particles;
591  ParticleList new_non_hadron_particles;
592 
593  Pythia8::Vec4 pSum = 0.;
594  event_intermediate_.reset();
595  /* Update the partonic intermediate state from PYTHIA output.
596  * Note that hadronization will be performed separately,
597  * after identification of strings and replacement of constituents. */
598  for (int i = 0; i < pythia_parton_->event.size(); i++) {
599  if (pythia_parton_->event[i].isFinal()) {
600  const int pdgid = pythia_parton_->event[i].id();
601  Pythia8::Vec4 pquark = pythia_parton_->event[i].p();
602  const double mass = pythia_parton_->particleData.m0(pdgid);
603 
604  const int status = pythia_parton_->event[i].status();
605  const int color = pythia_parton_->event[i].col();
606  const int anticolor = pythia_parton_->event[i].acol();
607 
608  pSum += pquark;
609  event_intermediate_.append(pdgid, status, color, anticolor, pquark, mass);
610  }
611  }
612  // add junctions to the intermediate state if there is any.
613  event_intermediate_.clearJunctions();
614  for (int i = 0; i < pythia_parton_->event.sizeJunction(); i++) {
615  const int kind = pythia_parton_->event.kindJunction(i);
616  std::array<int, 3> col;
617  for (int j = 0; j < 3; j++) {
618  col[j] = pythia_parton_->event.colJunction(i, j);
619  }
620  event_intermediate_.appendJunction(kind, col[0], col[1], col[2]);
621  }
622  /* The zeroth entry of event record is supposed to have the information
623  * on the whole system. Specify the total momentum and invariant mass. */
624  event_intermediate_[0].p(pSum);
625  event_intermediate_[0].m(pSum.mCalc());
626 
627  /* Replace quark constituents according to the excess of valence quarks
628  * and then rescale momenta of partons by constant factor
629  * to fulfill the energy-momentum conservation. */
630  bool correct_constituents =
631  restore_constituent(event_intermediate_, excess_quark, excess_antiq);
632  if (!correct_constituents) {
633  logg[LPythia].debug("failed to find correct partonic constituents.");
634  return false;
635  }
636 
637  int npart = event_intermediate_.size();
638  int ipart = 0;
639  while (ipart < npart) {
640  const int pdgid = event_intermediate_[ipart].id();
641  if (event_intermediate_[ipart].isFinal() &&
642  !event_intermediate_[ipart].isParton() &&
643  !pythia_parton_->particleData.isOctetHadron(pdgid)) {
644  logg[LPythia].debug("PDG ID from Pythia: ", pdgid);
645  FourVector momentum = reorient(event_intermediate_[ipart], evecBasisAB_);
646  logg[LPythia].debug("4-momentum from Pythia: ", momentum);
647  bool found_ptype =
648  append_intermediate_list(pdgid, momentum, new_non_hadron_particles);
649  if (!found_ptype) {
650  logg[LPythia].warn("PDG ID ", pdgid,
651  " does not exist in ParticleType - start over.");
652  final_state_success = false;
653  }
654  event_intermediate_.remove(ipart, ipart);
655  npart -= 1;
656  } else {
657  ipart += 1;
658  }
659  }
660 
661  bool hadronize_success = false;
662  bool find_forward_string = true;
663  logg[LPythia].debug("Hard non-diff: partonic process gives ",
664  event_intermediate_.size(), " partons.");
665  // identify and fragment strings until there is no parton left.
666  while (event_intermediate_.size() > 1) {
667  // dummy event to initialize the internal variables of PYTHIA.
668  pythia_hadron_->event.reset();
669  if (!pythia_hadron_->next()) {
670  logg[LPythia].debug(" Dummy event in hard string routine failed.");
671  hadronize_success = false;
672  break;
673  }
674 
675  if (event_intermediate_.sizeJunction() > 0) {
676  // identify string from a junction if there is any.
677  compose_string_junction(find_forward_string, event_intermediate_,
678  pythia_hadron_->event);
679  } else {
680  /* identify string from a most forward or backward parton.
681  * if there is no junction. */
682  compose_string_parton(find_forward_string, event_intermediate_,
683  pythia_hadron_->event);
684  }
685 
686  // fragment the (identified) string into hadrons.
687  hadronize_success = pythia_hadron_->forceHadronLevel(false);
688  logg[LPythia].debug("Pythia hadronized, success = ", hadronize_success);
689 
690  new_intermediate_particles.clear();
691  if (hadronize_success) {
692  for (int i = 0; i < event_hadron.size(); i++) {
693  if (event_hadron[i].isFinal()) {
694  int pythia_id = event_hadron[i].id();
695  logg[LPythia].debug("PDG ID from Pythia: ", pythia_id);
696  /* K_short and K_long need to be converted to K0
697  * since SMASH only knows K0 */
698  convert_KaonLS(pythia_id);
699 
700  /* evecBasisAB_[0] is a unit 3-vector in the collision axis,
701  * while evecBasisAB_[1] and evecBasisAB_[2] spans the transverse
702  * plane. Given that PYTHIA assumes z-direction to be the collision
703  * axis, pz from PYTHIA should be the momentum compoment in
704  * evecBasisAB_[0]. px and py are respectively the momentum components
705  * in two transverse directions evecBasisAB_[1] and evecBasisAB_[2].
706  */
707  FourVector momentum = reorient(event_hadron[i], evecBasisAB_);
708  logg[LPythia].debug("4-momentum from Pythia: ", momentum);
709  logg[LPythia].debug("appending the particle ", pythia_id,
710  " to the intermediate particle list.");
711  bool found_ptype = false;
712  if (event_hadron[i].isHadron()) {
713  found_ptype = append_intermediate_list(pythia_id, momentum,
714  new_intermediate_particles);
715  } else {
716  found_ptype = append_intermediate_list(pythia_id, momentum,
717  new_non_hadron_particles);
718  }
719  if (!found_ptype) {
720  logg[LPythia].warn("PDG ID ", pythia_id,
721  " does not exist in ParticleType - start over.");
722  hadronize_success = false;
723  }
724  }
725  }
726  }
727 
728  /* if hadronization is not successful,
729  * reset the event records, return false and then start over. */
730  if (!hadronize_success) {
731  break;
732  }
733 
734  FourVector uString = FourVector(1., 0., 0., 0.);
735  ThreeVector evec = find_forward_string ? evecBasisAB_[0] : -evecBasisAB_[0];
736  int nfrag = append_final_state(new_intermediate_particles, uString, evec);
737  NpartFinal_ += nfrag;
738 
739  find_forward_string = !find_forward_string;
740  }
741 
742  if (hadronize_success) {
743  // add the final state particles, which are not hadron.
744  for (ParticleData data : new_non_hadron_particles) {
745  data.set_cross_section_scaling_factor(1.);
746  data.set_formation_time(time_collision_);
747  final_state_.push_back(data);
748  }
749  } else {
750  final_state_.clear();
751  }
752 
753  return hadronize_success;
754 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ next_BBbarAnn()

bool smash::StringProcess::next_BBbarAnn ( )

Baryon-antibaryon annihilation process Based on what UrQMD Bass:1998ca [4], Bleicher:1999xi [8] does, it create two mesonic strings after annihilating one quark-antiquark pair.

Each string has mass equal to half of sqrts.

Returns
whether the process is successfully implemented.
Exceptions
std::invalid_argumentif incoming particles are not baryon-antibaryon pair

Definition at line 1504 of file processstring.cc.

1504  {
1505  const std::array<FourVector, 2> ustrcom = {FourVector(1., 0., 0., 0.),
1506  FourVector(1., 0., 0., 0.)};
1507 
1508  NpartFinal_ = 0;
1509  NpartString_[0] = 0;
1510  NpartString_[1] = 0;
1511  final_state_.clear();
1512 
1513  logg[LPythia].debug("Annihilation occurs between ", PDGcodes_[0], "+",
1514  PDGcodes_[1], " at CM energy [GeV] ", sqrtsAB_);
1515 
1516  // check if the initial state is baryon-antibaryon pair.
1517  PdgCode baryon = PDGcodes_[0], antibaryon = PDGcodes_[1];
1518  if (baryon.baryon_number() == -1) {
1519  std::swap(baryon, antibaryon);
1520  }
1521  if (baryon.baryon_number() != 1 || antibaryon.baryon_number() != -1) {
1522  throw std::invalid_argument("Expected baryon-antibaryon pair.");
1523  }
1524 
1525  // Count how many qqbar combinations are possible for each quark type
1526  constexpr int n_q_types = 5; // u, d, s, c, b
1527  std::vector<int> qcount_bar, qcount_antibar;
1528  std::vector<int> n_combinations;
1529  bool no_combinations = true;
1530  for (int i = 0; i < n_q_types; i++) {
1531  qcount_bar.push_back(baryon.net_quark_number(i + 1));
1532  qcount_antibar.push_back(-antibaryon.net_quark_number(i + 1));
1533  const int n_i = qcount_bar[i] * qcount_antibar[i];
1534  n_combinations.push_back(n_i);
1535  if (n_i > 0) {
1536  no_combinations = false;
1537  }
1538  }
1539 
1540  /* if it is a BBbar pair but there is no qqbar pair to annihilate,
1541  * nothing happens */
1542  if (no_combinations) {
1543  for (int i = 0; i < 2; i++) {
1544  NpartString_[i] = 1;
1545  ParticleData new_particle(ParticleType::find(PDGcodes_[i]));
1546  new_particle.set_4momentum(pcom_[i]);
1547  new_particle.set_cross_section_scaling_factor(1.);
1548  new_particle.set_formation_time(time_collision_);
1549  final_state_.push_back(new_particle);
1550  }
1552  return true;
1553  }
1554 
1555  // Select qqbar pair to annihilate and remove it away
1556  auto discrete_distr = random::discrete_dist<int>(n_combinations);
1557  const int q_annihilate = discrete_distr() + 1;
1558  qcount_bar[q_annihilate - 1]--;
1559  qcount_antibar[q_annihilate - 1]--;
1560 
1561  // Get the remaining quarks and antiquarks
1562  std::vector<int> remaining_quarks, remaining_antiquarks;
1563  for (int i = 0; i < n_q_types; i++) {
1564  for (int j = 0; j < qcount_bar[i]; j++) {
1565  remaining_quarks.push_back(i + 1);
1566  }
1567  for (int j = 0; j < qcount_antibar[i]; j++) {
1568  remaining_antiquarks.push_back(-(i + 1));
1569  }
1570  }
1571  assert(remaining_quarks.size() == 2);
1572  assert(remaining_antiquarks.size() == 2);
1573 
1574  const std::array<double, 2> mstr = {0.5 * sqrtsAB_, 0.5 * sqrtsAB_};
1575 
1576  // randomly select two quark-antiquark pairs
1577  if (random::uniform_int(0, 1) == 0) {
1578  std::swap(remaining_quarks[0], remaining_quarks[1]);
1579  }
1580  if (random::uniform_int(0, 1) == 0) {
1581  std::swap(remaining_antiquarks[0], remaining_antiquarks[1]);
1582  }
1583  // Make sure it satisfies kinematical threshold constraint
1584  bool kin_threshold_satisfied = true;
1585  for (int i = 0; i < 2; i++) {
1586  const double mstr_min =
1587  pythia_hadron_->particleData.m0(remaining_quarks[i]) +
1588  pythia_hadron_->particleData.m0(remaining_antiquarks[i]);
1589  if (mstr_min > mstr[i]) {
1590  kin_threshold_satisfied = false;
1591  }
1592  }
1593  if (!kin_threshold_satisfied) {
1594  return false;
1595  }
1596  // Fragment two strings
1597  for (int i = 0; i < 2; i++) {
1598  ParticleList new_intermediate_particles;
1599 
1600  ThreeVector evec = pcom_[i].threevec() / pcom_[i].threevec().abs();
1601  const int nfrag =
1602  fragment_string(remaining_quarks[i], remaining_antiquarks[i], mstr[i],
1603  evec, true, false, new_intermediate_particles);
1604  if (nfrag <= 0) {
1605  NpartString_[i] = 0;
1606  return false;
1607  }
1608  NpartString_[i] =
1609  append_final_state(new_intermediate_particles, ustrcom[i], evec);
1610  }
1612  return true;
1613 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ find_excess_constituent()

void smash::StringProcess::find_excess_constituent ( PdgCode pdg_actual,
PdgCode pdg_mapped,
std::array< int, 5 > &  excess_quark,
std::array< int, 5 > &  excess_antiq 
)
static

Compare the valence quark contents of the actual and mapped hadrons and evaluate how many more constituents the actual hadron has compared to the mapped one.

excess_quark[i - 1] is how many more quarks with flavor i (PDG id i) pdg_actual has compared to pdg_mapped. excess_antiq[i - 1] is how many more antiquarks with flavor i (PDG id -i) pdg_actual has compared to pdg_mapped.

Parameters
[in]pdg_actualPDG code of actual incoming particle.
[in]pdg_mappedPDG code of mapped particles used in PYTHIA event generation.
[out]excess_quarkexcess of quarks.
[out]excess_antiqexcess of anti-quarks.

Definition at line 756 of file processstring.cc.

759  {
760  /* decompose PDG id of the actual hadron and mapped one
761  * to get the valence quark constituents */
762  std::array<int, 3> qcontent_actual = pdg_actual.quark_content();
763  std::array<int, 3> qcontent_mapped = pdg_mapped.quark_content();
764 
765  excess_quark = {0, 0, 0, 0, 0};
766  excess_antiq = {0, 0, 0, 0, 0};
767  for (int i = 0; i < 3; i++) {
768  if (qcontent_actual[i] > 0) { // quark content of the actual hadron
769  int j = qcontent_actual[i] - 1;
770  excess_quark[j] += 1;
771  }
772 
773  if (qcontent_mapped[i] > 0) { // quark content of the mapped hadron
774  int j = qcontent_mapped[i] - 1;
775  excess_quark[j] -= 1;
776  }
777 
778  if (qcontent_actual[i] < 0) { // antiquark content of the actual hadron
779  int j = std::abs(qcontent_actual[i]) - 1;
780  excess_antiq[j] += 1;
781  }
782 
783  if (qcontent_mapped[i] < 0) { // antiquark content of the mapped hadron
784  int j = std::abs(qcontent_mapped[i]) - 1;
785  excess_antiq[j] -= 1;
786  }
787  }
788 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ replace_constituent()

void smash::StringProcess::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.

If the quark flavor i is converted into another flavor j, excess_constituent[i - 1] increases by 1 and excess_constituent[j - 1] decreases by 1. Note that this happens only if excess_constituent[i - 1] < 0 and excess_constituent[j - 1] > 0 (i.e., the incoming hadron has more constituents with flavor j and less constituents with flavor i, compared to the mapped hadron), so they get closer to 0 after the function call.

Parameters
[out]particlePYTHIA particle object to be converted.
[out]excess_constituentexcess in the number of quark constituents. If the particle has positive (negative) quark number, excess of quarks (anti-quarks) should be used.
See also
StringProcess::restore_constituent(Pythia8::Event &, std::array<std::array<int, 5>, 2> &, std::array<std::array<int, 5>, 2> &)

Definition at line 790 of file processstring.cc.

791  {
792  // If the particle is neither quark nor diquark, nothing to do.
793  if (!particle.isQuark() && !particle.isDiquark()) {
794  return;
795  }
796 
797  // If there is no excess of constituents, nothing to do.
798  const std::array<int, 5> excess_null = {0, 0, 0, 0, 0};
799  if (excess_constituent == excess_null) {
800  return;
801  }
802 
803  int nq = 0;
804  std::array<int, 2> pdgid = {0, 0};
805  int spin_deg = 0;
806  int pdgid_new = 0;
807  if (particle.isQuark()) {
808  nq = 1;
809  pdgid[0] = particle.id();
810  } else if (particle.isDiquark()) {
811  nq = 2;
812  quarks_from_diquark(particle.id(), pdgid[0], pdgid[1], spin_deg);
813  }
814 
815  for (int iq = 0; iq < nq; iq++) {
816  int jq = std::abs(pdgid[iq]) - 1;
817  int k_select = 0;
818  std::vector<int> k_found;
819  k_found.clear();
820  // check if the constituent needs to be converted.
821  if (excess_constituent[jq] < 0) {
822  for (int k = 0; k < 5; k++) {
823  // check which specie it can be converted into.
824  if (k != jq && excess_constituent[k] > 0) {
825  k_found.push_back(k);
826  }
827  }
828  }
829 
830  // make a random selection of specie and update the excess of constituent.
831  if (k_found.size() > 0) {
832  const int l =
833  random::uniform_int(0, static_cast<int>(k_found.size()) - 1);
834  k_select = k_found[l];
835  /* flavor jq + 1 is converted into k_select + 1
836  * and excess_constituent is updated. */
837  pdgid[iq] = pdgid[iq] > 0 ? k_select + 1 : -(k_select + 1);
838  excess_constituent[jq] += 1;
839  excess_constituent[k_select] -= 1;
840  }
841  }
842 
843  // determine PDG id of the converted parton.
844  if (particle.isQuark()) {
845  pdgid_new = pdgid[0];
846  } else if (particle.isDiquark()) {
847  if (std::abs(pdgid[0]) < std::abs(pdgid[1])) {
848  std::swap(pdgid[0], pdgid[1]);
849  }
850 
851  pdgid_new = std::abs(pdgid[0]) * 1000 + std::abs(pdgid[1]) * 100;
852  if (std::abs(pdgid[0]) == std::abs(pdgid[1])) {
853  pdgid_new += 3;
854  } else {
855  pdgid_new += spin_deg;
856  }
857 
858  if (particle.id() < 0) {
859  pdgid_new *= -1;
860  }
861  }
862  logg[LPythia].debug(" parton id = ", particle.id(), " is converted to ",
863  pdgid_new);
864 
865  // update the constituent mass and energy.
866  Pythia8::Vec4 pquark = particle.p();
867  double mass_new = pythia_hadron_->particleData.m0(pdgid_new);
868  double e_new = std::sqrt(mass_new * mass_new + pquark.pAbs() * pquark.pAbs());
869  // update the particle object.
870  particle.id(pdgid_new);
871  particle.e(e_new);
872  particle.m(mass_new);
873 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ find_total_number_constituent()

void smash::StringProcess::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 size 5.

Note that elements of the array (0, 1, 2, 3, 4) correspond to d, u, s, c, b flavors.

Parameters
[in]event_intermediatePYTHIA partonic event record which contains output from PYTHIA (hard) event generation.
[out]nquark_totaltotal number of quarks in the system. This is computed based on event_intermediate.
[out]nantiq_totaltotal number of antiquarks in the system. This is computed based on event_intermediate.

Definition at line 875 of file processstring.cc.

877  {
878  for (int iflav = 0; iflav < 5; iflav++) {
879  nquark_total[iflav] = 0;
880  nantiq_total[iflav] = 0;
881  }
882 
883  for (int ip = 1; ip < event_intermediate.size(); ip++) {
884  if (!event_intermediate[ip].isFinal()) {
885  continue;
886  }
887  const int pdgid = event_intermediate[ip].id();
888  if (pdgid > 0) {
889  // quarks
890  for (int iflav = 0; iflav < 5; iflav++) {
891  nquark_total[iflav] +=
892  pythia_hadron_->particleData.nQuarksInCode(pdgid, iflav + 1);
893  }
894  } else {
895  // antiquarks
896  for (int iflav = 0; iflav < 5; iflav++) {
897  nantiq_total[iflav] += pythia_hadron_->particleData.nQuarksInCode(
898  std::abs(pdgid), iflav + 1);
899  }
900  }
901  }
902 }
Here is the caller graph for this function:

◆ splitting_gluon_qqbar()

bool smash::StringProcess::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 into other flavors.

If that is not the case, a gluon is splitted into a quark-antiquark pair with desired flavor, so that their flavor can be changed afterwards. For example, if there is no antiquark in the system and we have excess_antiq = (1, -1, 0, 0, 0) (i.e., one ubar has to be converted into dbar), a gluon will be splitted into u-ubar pair.

Parameters
[out]event_intermediatePYTHIA partonic event record to be updated when a gluon happens to split into a qqbar pair.
[out]nquark_totaltotal number of quarks in the system. This is computed based on event_intermediate.
[out]nantiq_totaltotal number of antiquarks in the system. This is computed based on event_intermediate.
[in]sign_constituenttrue (false) if want to check quarks (antiquarks) and their excesses.
[in]excess_constituentexcess in the number of quark constituents. If sign_constituent is true (false), excess of quarks (anti-quarks) should be used.
Returns
false if there are not enough constituents and there is no gluon to split into desired quark-antiquark pair. Otherwise, it gives true.

Definition at line 904 of file processstring.cc.

907  {
908  Pythia8::Vec4 pSum = event_intermediate[0].p();
909 
910  /* compute total number of quark and antiquark constituents
911  * in the whole system. */
912  find_total_number_constituent(event_intermediate, nquark_total, nantiq_total);
913 
914  for (int iflav = 0; iflav < 5; iflav++) {
915  /* Find how many constituent will be in the system after
916  * changing the flavors.
917  * Note that nquark_total is number of constituent right after
918  * the pythia event (with mapped incoming hadrons), while the excess
919  * shows how many constituents we have more or less that nquark_total. */
920  int nquark_final =
921  excess_constituent[0][iflav] + excess_constituent[1][iflav];
922  if (sign_constituent) {
923  nquark_final += nquark_total[iflav];
924  } else {
925  nquark_final += nantiq_total[iflav];
926  }
927  /* Therefore, nquark_final should not be negative.
928  * negative nquark_final means that it will not be possible to
929  * find a constituent to change the flavor. */
930  bool enough_quark = nquark_final >= 0;
931  /* If that is the case, a gluon will be splitted into
932  * a quark-antiquark pair with the desired flavor. */
933  if (!enough_quark) {
934  logg[LPythia].debug(" not enough constituents with flavor ", iflav + 1,
935  " : try to split a gluon to qqbar.");
936  for (int ic = 0; ic < std::abs(nquark_final); ic++) {
937  /* Since each incoming hadron has its own count of the excess,
938  * it is necessary to find which one is problematic. */
939  int ih_mod = -1;
940  if (excess_constituent[0][iflav] < 0) {
941  ih_mod = 0;
942  } else {
943  ih_mod = 1;
944  }
945 
946  /* find the most forward or backward gluon
947  * depending on which incoming hadron is found to be an issue. */
948  int iforward = 1;
949  for (int ip = 2; ip < event_intermediate.size(); ip++) {
950  if (!event_intermediate[ip].isFinal() ||
951  !event_intermediate[ip].isGluon()) {
952  continue;
953  }
954 
955  const double y_gluon_current = event_intermediate[ip].y();
956  const double y_gluon_forward = event_intermediate[iforward].y();
957  if ((ih_mod == 0 && y_gluon_current > y_gluon_forward) ||
958  (ih_mod == 1 && y_gluon_current < y_gluon_forward)) {
959  iforward = ip;
960  }
961  }
962 
963  if (!event_intermediate[iforward].isGluon()) {
964  logg[LPythia].debug("There is no gluon to split into qqbar.");
965  return false;
966  }
967 
968  // four momentum of the original gluon
969  Pythia8::Vec4 pgluon = event_intermediate[iforward].p();
970 
971  const int pdgid = iflav + 1;
972  const double mass = pythia_hadron_->particleData.m0(pdgid);
973  const int status = event_intermediate[iforward].status();
974  /* color and anticolor indices.
975  * the color index of gluon goes to the quark, while
976  * the anticolor index goes to the antiquark */
977  const int col = event_intermediate[iforward].col();
978  const int acol = event_intermediate[iforward].acol();
979 
980  // three momenta of quark and antiquark
981  std::array<double, 2> px_quark;
982  std::array<double, 2> py_quark;
983  std::array<double, 2> pz_quark;
984  // energies of quark and antiquark
985  std::array<double, 2> e_quark;
986  // four momenta of quark and antiquark
987  std::array<Pythia8::Vec4, 2> pquark;
988  // transverse momentum scale of string fragmentation
989  const double sigma_qt_frag = pythia_hadron_->parm("StringPT:sigma");
990  // sample relative transverse momentum between quark and antiquark
991  const double qx = random::normal(0., sigma_qt_frag * M_SQRT1_2);
992  const double qy = random::normal(0., sigma_qt_frag * M_SQRT1_2);
993  // setup kinematics
994  for (int isign = 0; isign < 2; isign++) {
995  /* As the simplest assumption, the three momentum of gluon
996  * is equally distributed to quark and antiquark.
997  * Then, they have a relative transverse momentum. */
998  px_quark[isign] = 0.5 * pgluon.px() + (isign == 0 ? 1. : -1.) * qx;
999  py_quark[isign] = 0.5 * pgluon.py() + (isign == 0 ? 1. : -1.) * qy;
1000  pz_quark[isign] = 0.5 * pgluon.pz();
1001  e_quark[isign] =
1002  std::sqrt(mass * mass + px_quark[isign] * px_quark[isign] +
1003  py_quark[isign] * py_quark[isign] +
1004  pz_quark[isign] * pz_quark[isign]);
1005  pquark[isign] = Pythia8::Vec4(px_quark[isign], py_quark[isign],
1006  pz_quark[isign], e_quark[isign]);
1007  }
1008 
1009  /* Total energy is not conserved at this point,
1010  * but this will be cured later. */
1011  pSum += pquark[0] + pquark[1] - pgluon;
1012  // add quark and antiquark to the event record
1013  event_intermediate.append(pdgid, status, col, 0, pquark[0], mass);
1014  event_intermediate.append(-pdgid, status, 0, acol, pquark[1], mass);
1015  // then remove the gluon from the record
1016  event_intermediate.remove(iforward, iforward);
1017 
1018  logg[LPythia].debug(" gluon at iforward = ", iforward,
1019  " is splitted into ", pdgid, ",", -pdgid,
1020  " qqbar pair.");
1021  /* Increase the total number of quarks and antiquarks by 1,
1022  * as we have extra ones from a gluon. */
1023  nquark_total[iflav] += 1;
1024  nantiq_total[iflav] += 1;
1025  }
1026  }
1027  }
1028 
1029  /* The zeroth entry of event record is supposed to have the information
1030  * on the whole system. Specify the total momentum and invariant mass. */
1031  event_intermediate[0].p(pSum);
1032  event_intermediate[0].m(pSum.mCalc());
1033 
1034  return true;
1035 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ rearrange_excess()

void smash::StringProcess::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 into other flavors.

If that is not the case, excesses of quarks and antiquarks are modified such that the net quark number of each flavor is conserved. For example, if there is no antiquark in the system and we have excess_antiq = (1, -1, 0, 0, 0) (i.e., one ubar has to be converted into dbar), excess_antiq will be changed into (0, 0, 0, 0, 0) and (-1, 1, 0, 0, 0) will be added to excess_quark (i.e., one d quark has to be converted into u quark instead).

Number of quarks is checked if the first argument is the total number of quarks, and the second and third arguments are respectively excesses of quarks and antiquarks. Number of antiquarks is checked if the first argument is the total number of antiquarks, and the second and third arguments are respectively excesses of antiquarks and quarks.

Parameters
[in]nquark_totaltotal number of quarks (antiquarks) in the system.
[out]excess_quarkexcess of quarks (antiquarks) in incoming particles, compared to the mapped ones.
[out]excess_antiqexcess of anti-quarks (quarks) in incoming particles, compared to the mapped ones.

Definition at line 1037 of file processstring.cc.

1040  {
1041  for (int iflav = 0; iflav < 5; iflav++) {
1042  /* Find how many constituent will be in the system after
1043  * changing the flavors.
1044  * Note that nquark_total is number of constituent right after
1045  * the pythia event (with mapped incoming hadrons), while the excess
1046  * shows how many constituents we have more or less that nquark_total. */
1047  int nquark_final =
1048  nquark_total[iflav] + excess_quark[0][iflav] + excess_quark[1][iflav];
1049  /* Therefore, nquark_final should not be negative.
1050  * negative nquark_final means that it will not be possible to
1051  * find a constituent to change the flavor. */
1052  bool enough_quark = nquark_final >= 0;
1053  // If that is the case, excess of constituents will be modified
1054  if (!enough_quark) {
1055  logg[LPythia].debug(" not enough constituents with flavor ", iflav + 1,
1056  " : try to modify excess of constituents.");
1057  for (int ic = 0; ic < std::abs(nquark_final); ic++) {
1058  /* Since each incoming hadron has its own count of the excess,
1059  * it is necessary to find which one is problematic. */
1060  int ih_mod = -1;
1061  if (excess_quark[0][iflav] < 0) {
1062  ih_mod = 0;
1063  } else {
1064  ih_mod = 1;
1065  }
1066  /* Increase the excess of both quark and antiquark
1067  * with corresponding flavor (iflav + 1) by 1.
1068  * This is for conservation of the net quark number. */
1069  excess_quark[ih_mod][iflav] += 1;
1070  excess_antiq[ih_mod][iflav] += 1;
1071 
1072  /* Since incoming hadrons are mapped onto ones with
1073  * the same baryon number (or quark number),
1074  * summation of the excesses over all flavors should be zero.
1075  * Therefore, we need to find another flavor which has
1076  * a positive excess and subtract by 1. */
1077  for (int jflav = 0; jflav < 5; jflav++) {
1078  // another flavor with positive excess of constituents
1079  if (jflav != iflav && excess_quark[ih_mod][jflav] > 0) {
1080  /* Decrease the excess of both quark and antiquark
1081  * with corresponding flavor (jflav + 1) by 1. */
1082  excess_quark[ih_mod][jflav] -= 1;
1083  excess_antiq[ih_mod][jflav] -= 1;
1084  /* We only need to find one (another) flavor to subtract.
1085  * No more! */
1086  break;
1087  }
1088  }
1089  }
1090  }
1091  }
1092 }
Here is the caller graph for this function:

◆ restore_constituent()

bool smash::StringProcess::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 into the desired ones according to the excess of quarks and anti-quarks.

Quark (antiquark) flavor is changed and excess of quark (antiquark) is also updated by calling StringProcess::replace_constituent. Beginning with the most forward (or backward) constituent, conversion is done until the total net quark number of each flavor is same with that of incoming hadrons. (i.e., excess_quark minus excess_antiq of incoming hadrons becomes zero.)

However, note that there are some circumstances where this procedure is not directly carried out. For example, a proton-kaon(+) collision mapped onto a proton-pion(+) might be an issue if it involves d + dbar -> g g partonic interaction, given that we anticipate to change dbar to sbar. If such case occurs, we first try to split gluon into quark-antiquark pair with desired flavor. If there are not enough gluons to split, we try to modify the excesses of constituents such that the net quark number is conserved.

Parameters
[out]event_intermediatePYTHIA partonic event record to be updated according to the valence quark contents of incoming hadrons.
[out]excess_quarkexcess of quarks in incoming particles, compared to the mapped ones.
[out]excess_antiqexcess of anti-quarks in incoming particles, compared to the mapped ones.
See also
StringProcess::replace_constituent(Pythia8::Particle &, std::array<int, 5> &)
StringProcess::splitting_gluon_qqbar(Pythia8::Event &, std::array<int, 5> &, std::array<int, 5> &, bool, std::array<std::array<int, 5>, 2> &)
StringProcess::rearrange_excess(std::array<int, 5> &, std::array<std::array<int, 5>, 2> &, std::array<std::array<int, 5>, 2> &)

Definition at line 1094 of file processstring.cc.

1097  {
1098  Pythia8::Vec4 pSum = event_intermediate[0].p();
1099  const double energy_init = pSum.e();
1100  logg[LPythia].debug(" initial total energy [GeV] : ", energy_init);
1101 
1102  // Total number of quarks and antiquarks, respectively.
1103  std::array<int, 5> nquark_total;
1104  std::array<int, 5> nantiq_total;
1105 
1106  /* Split a gluon into qqbar if we do not have enough constituents
1107  * to be converted in the system. */
1108  bool split_for_quark = splitting_gluon_qqbar(
1109  event_intermediate, nquark_total, nantiq_total, true, excess_quark);
1110  bool split_for_antiq = splitting_gluon_qqbar(
1111  event_intermediate, nquark_total, nantiq_total, false, excess_antiq);
1112 
1113  /* Modify excess_quark and excess_antiq if we do not have enough constituents
1114  * to be converted in the system. */
1115  if (!split_for_quark || !split_for_antiq) {
1116  rearrange_excess(nquark_total, excess_quark, excess_antiq);
1117  rearrange_excess(nantiq_total, excess_antiq, excess_quark);
1118  }
1119 
1120  // Final check if there are enough constituents.
1121  for (int iflav = 0; iflav < 5; iflav++) {
1122  if (nquark_total[iflav] + excess_quark[0][iflav] + excess_quark[1][iflav] <
1123  0) {
1124  logg[LPythia].debug("Not enough quark constituents of flavor ",
1125  iflav + 1);
1126  return false;
1127  }
1128 
1129  if (nantiq_total[iflav] + excess_antiq[0][iflav] + excess_antiq[1][iflav] <
1130  0) {
1131  logg[LPythia].debug("Not enough antiquark constituents of flavor ",
1132  -(iflav + 1));
1133  return false;
1134  }
1135  }
1136 
1137  for (int ih = 0; ih < 2; ih++) {
1138  logg[LPythia].debug(" initial excess_quark[", ih, "] = (",
1139  excess_quark[ih][0], ", ", excess_quark[ih][1], ", ",
1140  excess_quark[ih][2], ", ", excess_quark[ih][3], ", ",
1141  excess_quark[ih][4], ")");
1142  logg[LPythia].debug(" initial excess_antiq[", ih, "] = (",
1143  excess_antiq[ih][0], ", ", excess_antiq[ih][1], ", ",
1144  excess_antiq[ih][2], ", ", excess_antiq[ih][3], ", ",
1145  excess_antiq[ih][4], ")");
1146  }
1147 
1148  bool recovered_quarks = false;
1149  while (!recovered_quarks) {
1150  /* Flavor conversion begins with the most forward and backward parton
1151  * respectively for incoming_particles_[0] and incoming_particles_[1]. */
1152  std::array<bool, 2> find_forward = {true, false};
1153  const std::array<int, 5> excess_null = {0, 0, 0, 0, 0};
1154  std::array<int, 5> excess_total = excess_null;
1155 
1156  for (int ih = 0; ih < 2; ih++) { // loop over incoming hadrons
1157  int nfrag = event_intermediate.size();
1158  for (int np_end = 0; np_end < nfrag - 1; np_end++) { // constituent loop
1159  /* select the np_end-th most forward or backward parton and
1160  * change its specie.
1161  * np_end = 0 corresponds to the most forward,
1162  * np_end = 1 corresponds to the second most forward and so on. */
1163  int iforward =
1164  get_index_forward(find_forward[ih], np_end, event_intermediate);
1165  pSum -= event_intermediate[iforward].p();
1166 
1167  if (event_intermediate[iforward].id() > 0) { // quark and diquark
1168  replace_constituent(event_intermediate[iforward], excess_quark[ih]);
1169  logg[LPythia].debug(
1170  " excess_quark[", ih, "] = (", excess_quark[ih][0], ", ",
1171  excess_quark[ih][1], ", ", excess_quark[ih][2], ", ",
1172  excess_quark[ih][3], ", ", excess_quark[ih][4], ")");
1173  } else { // antiquark and anti-diquark
1174  replace_constituent(event_intermediate[iforward], excess_antiq[ih]);
1175  logg[LPythia].debug(
1176  " excess_antiq[", ih, "] = (", excess_antiq[ih][0], ", ",
1177  excess_antiq[ih][1], ", ", excess_antiq[ih][2], ", ",
1178  excess_antiq[ih][3], ", ", excess_antiq[ih][4], ")");
1179  }
1180 
1181  const int pdgid = event_intermediate[iforward].id();
1182  Pythia8::Vec4 pquark = event_intermediate[iforward].p();
1183  const double mass = pythia_hadron_->particleData.m0(pdgid);
1184 
1185  const int status = event_intermediate[iforward].status();
1186  const int color = event_intermediate[iforward].col();
1187  const int anticolor = event_intermediate[iforward].acol();
1188 
1189  pSum += pquark;
1190  event_intermediate.append(pdgid, status, color, anticolor, pquark,
1191  mass);
1192 
1193  event_intermediate.remove(iforward, iforward);
1194  /* Now the last np_end + 1 entries in event_intermediate
1195  * are np_end + 1 most forward (or backward) partons. */
1196  }
1197 
1198  // Compute the excess of net quark numbers.
1199  for (int j = 0; j < 5; j++) {
1200  excess_total[j] += (excess_quark[ih][j] - excess_antiq[ih][j]);
1201  }
1202  }
1203 
1204  /* If there is no excess of net quark numbers,
1205  * quark content is considered to be correct. */
1206  recovered_quarks = excess_total == excess_null;
1207  }
1208  logg[LPythia].debug(" valence quark contents of hadons are recovered.");
1209 
1210  logg[LPythia].debug(" current total energy [GeV] : ", pSum.e());
1211  /* rescale momenta of all partons by a constant factor
1212  * to conserve the total energy. */
1213  while (true) {
1214  if (std::abs(pSum.e() - energy_init) < really_small * energy_init) {
1215  break;
1216  }
1217 
1218  double energy_current = pSum.e();
1219  double slope = 0.;
1220  for (int i = 1; i < event_intermediate.size(); i++) {
1221  slope += event_intermediate[i].pAbs2() / event_intermediate[i].e();
1222  }
1223 
1224  const double rescale_factor = 1. + (energy_init - energy_current) / slope;
1225  pSum = 0.;
1226  for (int i = 1; i < event_intermediate.size(); i++) {
1227  const double px = rescale_factor * event_intermediate[i].px();
1228  const double py = rescale_factor * event_intermediate[i].py();
1229  const double pz = rescale_factor * event_intermediate[i].pz();
1230  const double pabs = rescale_factor * event_intermediate[i].pAbs();
1231  const double mass = event_intermediate[i].m();
1232 
1233  event_intermediate[i].px(px);
1234  event_intermediate[i].py(py);
1235  event_intermediate[i].pz(pz);
1236  event_intermediate[i].e(std::sqrt(mass * mass + pabs * pabs));
1237  pSum += event_intermediate[i].p();
1238  }
1239  logg[LPythia].debug(" parton momenta are rescaled by factor of ",
1240  rescale_factor);
1241  }
1242 
1243  logg[LPythia].debug(" final total energy [GeV] : ", pSum.e());
1244  /* The zeroth entry of event record is supposed to have the information
1245  * on the whole system. Specify the total momentum and invariant mass. */
1246  event_intermediate[0].p(pSum);
1247  event_intermediate[0].m(pSum.mCalc());
1248 
1249  return true;
1250 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ compose_string_parton()

void smash::StringProcess::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 event record.

All partons found are moved into a new event record for the further hadronization process. Note that col and acol of Pythia8::Particle contain information on the color flow. This function begins with the most forward (or backward) parton.

For example, quark (col = 1, acol = 0), gluon (col = 2, acol = 1) and antiquark (col = 0, acol = 2) correspond to a \( \bar{q} \, g \, q \) mesonic string. quark (col = 1, acol = 0) and diquark (col = 0, acol = 1) correspond to a \( qq \, q\) baryonic string.

Parameters
[in]find_forward_stringIf it is set to be true (false), it begins with forward (backward) parton.
[out]event_intermediatePYTHIA event record from which a string is identified. All partons found here are removed.
[out]event_hadronizePYTHIA event record to which partons in a string are added.

Definition at line 1252 of file processstring.cc.

1254  {
1255  Pythia8::Vec4 pSum = 0.;
1256  event_hadronize.reset();
1257 
1258  // select the most forward or backward parton.
1259  int iforward = get_index_forward(find_forward_string, 0, event_intermediate);
1260  logg[LPythia].debug("Hard non-diff: iforward = ", iforward, "(",
1261  event_intermediate[iforward].id(), ")");
1262 
1263  pSum += event_intermediate[iforward].p();
1264  event_hadronize.append(event_intermediate[iforward]);
1265 
1266  int col_to_find = event_intermediate[iforward].acol();
1267  int acol_to_find = event_intermediate[iforward].col();
1268  event_intermediate.remove(iforward, iforward);
1269  logg[LPythia].debug("Hard non-diff: event_intermediate reduces in size to ",
1270  event_intermediate.size());
1271 
1272  // trace color and anti-color indices and find corresponding partons.
1273  while (col_to_find != 0 || acol_to_find != 0) {
1274  logg[LPythia].debug(" col_to_find = ", col_to_find,
1275  ", acol_to_find = ", acol_to_find);
1276 
1277  int ifound = -1;
1278  for (int i = 1; i < event_intermediate.size(); i++) {
1279  const int pdgid = event_intermediate[i].id();
1280  bool found_col =
1281  col_to_find != 0 && col_to_find == event_intermediate[i].col();
1282  bool found_acol =
1283  acol_to_find != 0 && acol_to_find == event_intermediate[i].acol();
1284  if (found_col) {
1285  logg[LPythia].debug(" col_to_find ", col_to_find, " from i ", i, "(",
1286  pdgid, ") found");
1287  }
1288  if (found_acol) {
1289  logg[LPythia].debug(" acol_to_find ", acol_to_find, " from i ", i, "(",
1290  pdgid, ") found");
1291  }
1292 
1293  if (found_col && !found_acol) {
1294  ifound = i;
1295  col_to_find = event_intermediate[i].acol();
1296  break;
1297  } else if (!found_col && found_acol) {
1298  ifound = i;
1299  acol_to_find = event_intermediate[i].col();
1300  break;
1301  } else if (found_col && found_acol) {
1302  ifound = i;
1303  col_to_find = 0;
1304  acol_to_find = 0;
1305  break;
1306  }
1307  }
1308 
1309  if (ifound < 0) {
1310  event_intermediate.list();
1311  event_intermediate.listJunctions();
1312  event_hadronize.list();
1313  event_hadronize.listJunctions();
1314  if (col_to_find != 0) {
1315  logg[LPythia].error("No parton with col = ", col_to_find);
1316  }
1317  if (acol_to_find != 0) {
1318  logg[LPythia].error("No parton with acol = ", acol_to_find);
1319  }
1320  throw std::runtime_error("Hard string could not be identified.");
1321  } else {
1322  pSum += event_intermediate[ifound].p();
1323  // add a parton to the new event record.
1324  event_hadronize.append(event_intermediate[ifound]);
1325  // then remove from the original event record.
1326  event_intermediate.remove(ifound, ifound);
1327  logg[LPythia].debug(
1328  "Hard non-diff: event_intermediate reduces in size to ",
1329  event_intermediate.size());
1330  }
1331  }
1332 
1333  /* The zeroth entry of event record is supposed to have the information
1334  * on the whole system. Specify the total momentum and invariant mass. */
1335  event_hadronize[0].p(pSum);
1336  event_hadronize[0].m(pSum.mCalc());
1337 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ compose_string_junction()

void smash::StringProcess::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, from a given PYTHIA event record.

All partons found are moved into a new event record for the further hadronization process. Junction topology in PYTHIA combines three quarks (antiquarks) to make a color-neutral baryonic (anti-baryonic) configuration. A junction (anti-junction) carries three color (anti-color) indices which are connected with quarks (antiquarks). This function begins with the first junction.

For example, if there is a kind-1 junction with legs (col = 1, 2 and 3), it will first look for three partons with color indices col = 1, 2 and 3 and trace color indices until each leg is `‘closed’' with quark. If there is no quark in the end, there should be an anti-junction and its legs are connected to partons with corresponding anti-colors.

Parameters
[out]find_forward_stringIf it is set to be true (false), it is a string in the forward (backward) direction.
[out]event_intermediatePYTHIA event record from which a string is identified. All partons and junction(s) found here are removed.
[out]event_hadronizePYTHIA event record to which partons in a string are added.
See also
StringProcess::find_junction_leg(bool, std::vector<int> &, Pythia8::Event &, Pythia8::Event &)

Definition at line 1339 of file processstring.cc.

1341  {
1342  event_hadronize.reset();
1343 
1344  /* Move the first junction to the event record for hadronization
1345  * and specify color or anti-color indices to be found.
1346  * If junction kind is an odd number, it connects three quarks
1347  * to make a color-neutral baryonic configuration.
1348  * Otherwise, it connects three antiquarks
1349  * to make a color-neutral anti-baryonic configuration. */
1350  const int kind = event_intermediate.kindJunction(0);
1351  bool sign_color = kind % 2 == 1;
1352  std::vector<int> col; // color or anti-color indices of the junction legs
1353  for (int j = 0; j < 3; j++) {
1354  col.push_back(event_intermediate.colJunction(0, j));
1355  }
1356  event_hadronize.appendJunction(kind, col[0], col[1], col[2]);
1357  event_intermediate.eraseJunction(0);
1358  logg[LPythia].debug("junction (", col[0], ", ", col[1], ", ", col[2],
1359  ") with kind ", kind, " will be handled.");
1360 
1361  bool found_string = false;
1362  while (!found_string) {
1363  // trace color or anti-color indices and find corresponding partons.
1364  find_junction_leg(sign_color, col, event_intermediate, event_hadronize);
1365  found_string = true;
1366  for (unsigned int j = 0; j < col.size(); j++) {
1367  found_string = found_string && col[j] == 0;
1368  }
1369  if (!found_string) {
1370  /* if there is any leg which is not closed with parton,
1371  * look over junctions and find connected ones. */
1372  logg[LPythia].debug(" still has leg(s) unfinished.");
1373  sign_color = !sign_color;
1374  std::vector<int> junction_to_move;
1375  for (int i = 0; i < event_intermediate.sizeJunction(); i++) {
1376  const int kind_new = event_intermediate.kindJunction(i);
1377  /* If the original junction is associated with positive baryon number,
1378  * it looks for anti-junctions whose legs are connected with
1379  * anti-quarks (anti-colors in general). */
1380  if (sign_color != (kind_new % 2 == 1)) {
1381  continue;
1382  }
1383 
1384  std::array<int, 3> col_new;
1385  for (int k = 0; k < 3; k++) {
1386  col_new[k] = event_intermediate.colJunction(i, k);
1387  }
1388 
1389  int n_legs_connected = 0;
1390  // loop over remaining legs
1391  for (unsigned int j = 0; j < col.size(); j++) {
1392  if (col[j] == 0) {
1393  continue;
1394  }
1395  for (int k = 0; k < 3; k++) {
1396  if (col[j] == col_new[k]) {
1397  n_legs_connected += 1;
1398  col[j] = 0;
1399  col_new[k] = 0;
1400  }
1401  }
1402  }
1403 
1404  // specify which junction is connected to the original one.
1405  if (n_legs_connected > 0) {
1406  for (int k = 0; k < 3; k++) {
1407  if (col_new[k] != 0) {
1408  col.push_back(col_new[k]);
1409  }
1410  }
1411  logg[LPythia].debug(" junction ", i, " (",
1412  event_intermediate.colJunction(i, 0), ", ",
1413  event_intermediate.colJunction(i, 1), ", ",
1414  event_intermediate.colJunction(i, 2),
1415  ") with kind ", kind_new, " will be added.");
1416  junction_to_move.push_back(i);
1417  }
1418  }
1419 
1420  /* If there is any connected junction,
1421  * move it to the event record for hadronization. */
1422  for (unsigned int i = 0; i < junction_to_move.size(); i++) {
1423  unsigned int imove = junction_to_move[i] - i;
1424  const int kind_add = event_intermediate.kindJunction(imove);
1425  std::array<int, 3> col_add;
1426  for (int k = 0; k < 3; k++) {
1427  col_add[k] = event_intermediate.colJunction(imove, k);
1428  }
1429  // add a junction to the new event record.
1430  event_hadronize.appendJunction(kind_add, col_add[0], col_add[1],
1431  col_add[2]);
1432  // then remove from the original event record.
1433  event_intermediate.eraseJunction(imove);
1434  }
1435  }
1436  }
1437 
1438  Pythia8::Vec4 pSum = event_hadronize[0].p();
1439  find_forward_string = pSum.pz() > 0.;
1440 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ find_junction_leg()

void smash::StringProcess::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.

All partons found are moved into a new event record for the further hadronization process.

Parameters
[in]sign_colortrue (false) if the junction is associated with color (anti-color) indices, corresponding baryonic (anti-baryonic) string
[out]colset of color indices that need to be found. The value is set to be zero once the corresponding partons are found.
[out]event_intermediatePYTHIA event record from which a string is identified. All partons and junction(s) found here are removed.
[out]event_hadronizePYTHIA event record to which partons in a string are added.
See also
StringProcess::compose_string_junction(bool &, Pythia8::Event &, Pythia8::Event &)

Definition at line 1442 of file processstring.cc.

1444  {
1445  Pythia8::Vec4 pSum = event_hadronize[0].p();
1446  for (unsigned int j = 0; j < col.size(); j++) {
1447  if (col[j] == 0) {
1448  continue;
1449  }
1450  bool found_leg = false;
1451  while (!found_leg) {
1452  int ifound = -1;
1453  for (int i = 1; i < event_intermediate.size(); i++) {
1454  const int pdgid = event_intermediate[i].id();
1455  if (sign_color && col[j] == event_intermediate[i].col()) {
1456  logg[LPythia].debug(" col[", j, "] = ", col[j], " from i ", i, "(",
1457  pdgid, ") found");
1458  ifound = i;
1459  col[j] = event_intermediate[i].acol();
1460  break;
1461  } else if (!sign_color && col[j] == event_intermediate[i].acol()) {
1462  logg[LPythia].debug(" acol[", j, "] = ", col[j], " from i ", i, "(",
1463  pdgid, ") found");
1464  ifound = i;
1465  col[j] = event_intermediate[i].col();
1466  break;
1467  }
1468  }
1469 
1470  if (ifound < 0) {
1471  found_leg = true;
1472  if (event_intermediate.sizeJunction() == 0) {
1473  event_intermediate.list();
1474  event_intermediate.listJunctions();
1475  event_hadronize.list();
1476  event_hadronize.listJunctions();
1477  logg[LPythia].error("No parton with col = ", col[j],
1478  " connected with junction leg ", j);
1479  throw std::runtime_error("Hard string could not be identified.");
1480  }
1481  } else {
1482  pSum += event_intermediate[ifound].p();
1483  // add a parton to the new event record.
1484  event_hadronize.append(event_intermediate[ifound]);
1485  // then remove from the original event record.
1486  event_intermediate.remove(ifound, ifound);
1487  logg[LPythia].debug(
1488  "Hard non-diff: event_intermediate reduces in size to ",
1489  event_intermediate.size());
1490  if (col[j] == 0) {
1491  found_leg = true;
1492  }
1493  }
1494  }
1495  }
1496 
1497  /* The zeroth entry of event record is supposed to have the information
1498  * on the whole system. Specify the total momentum and invariant mass. */
1499  event_hadronize[0].p(pSum);
1500  event_hadronize[0].m(pSum.mCalc());
1501 }
Here is the caller graph for this function:

◆ get_index_forward()

int smash::StringProcess::get_index_forward ( bool  find_forward,
int  np_end,
Pythia8::Event &  event 
)
inline

Obtain index of the most forward or backward particle in a given PYTHIA event record.

Parameters
[in]find_forwardif it looks for the most forward or backward particle.
[in]np_endnumber of the last particle entries to be excluded in lookup. In other words, it finds the most forward (or backward) particle among event[1, ... , event.size() - 1 - np_end].
[in]eventPYTHIA event record which contains particle entries. Note that event[0] is reserved for information on the entire system.
Returns
index of the selected particle, which is used to access the specific particle entry in the event record.

Definition at line 747 of file processstring.h.

748  {
749  int iforward = 1;
750  for (int ip = 2; ip < event.size() - np_end; ip++) {
751  const double y_quark_current = event[ip].y();
752  const double y_quark_forward = event[iforward].y();
753  if ((find_forward && y_quark_current > y_quark_forward) ||
754  (!find_forward && y_quark_current < y_quark_forward)) {
755  iforward = ip;
756  }
757  }
758  return iforward;
759  }
Here is the caller graph for this function:

◆ get_final_state()

ParticleList smash::StringProcess::get_final_state ( )
inline

a function to get the final state particle list which is called after the collision

Returns
ParticleList filled with the final state particles.

Definition at line 766 of file processstring.h.

766 { return final_state_; }
Here is the caller graph for this function:

◆ append_final_state()

int smash::StringProcess::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:1983ia [2].

Parameters
[out]intermediate_particleslist of fragmented particles to be appended
[in]uStringis velocity four vector of the string.
[in]evecLongis unit 3-vector in which string is stretched.
Returns
number of hadrons fragmented out of string.
Exceptions
std::invalid_argumentif fragmented particle is not hadron
std::invalid_argumentif string is neither mesonic nor baryonic

Definition at line 144 of file processstring.cc.

146  {
147  int nfrag = 0;
148  int bstring = 0;
149 
150  for (ParticleData &data : intermediate_particles) {
151  nfrag += 1;
152  bstring += data.pdgcode().baryon_number();
153  }
154  assert(nfrag > 0);
155 
156  /* compute the cross section scaling factor for leading hadrons
157  * based on the number of valence quarks. */
158  assign_all_scaling_factors(bstring, intermediate_particles, evecLong,
160 
161  // Velocity three-vector to perform Lorentz boost.
162  const ThreeVector vstring = uString.velocity();
163 
164  // compute the formation times of hadrons
165  for (int i = 0; i < nfrag; i++) {
166  ThreeVector velocity = intermediate_particles[i].momentum().velocity();
167  double gamma = 1. / intermediate_particles[i].inverse_gamma();
168  // boost 4-momentum into the center of mass frame
169  FourVector momentum =
170  intermediate_particles[i].momentum().lorentz_boost(-vstring);
171  intermediate_particles[i].set_4momentum(momentum);
172 
174  // set the formation time and position in the rest frame of string
175  double tau_prod = M_SQRT2 * intermediate_particles[i].effective_mass() /
177  double t_prod = tau_prod * gamma;
178  FourVector fragment_position = FourVector(t_prod, t_prod * velocity);
179  /* boost formation position into the center of mass frame
180  * and then into the lab frame */
181  fragment_position = fragment_position.lorentz_boost(-vstring);
182  fragment_position = fragment_position.lorentz_boost(-vcomAB_);
183  intermediate_particles[i].set_slow_formation_times(
185  soft_t_form_ * fragment_position.x0() + time_collision_);
186  } else {
187  ThreeVector v_calc = momentum.lorentz_boost(-vcomAB_).velocity();
188  double gamma_factor = 1.0 / std::sqrt(1 - (v_calc).sqr());
189  intermediate_particles[i].set_slow_formation_times(
191  time_formation_const_ * gamma_factor + time_collision_);
192  }
193 
194  final_state_.push_back(intermediate_particles[i]);
195  }
196 
197  return nfrag;
198 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ append_intermediate_list()

static bool smash::StringProcess::append_intermediate_list ( int  pdgid,
FourVector  momentum,
ParticleList &  intermediate_particles 
)
inlinestatic

append new particle from PYTHIA to a specific particle list

Parameters
[in]pdgidPDG id of particle
[in]momentumfour-momentum of particle
[out]intermediate_particlesparticle list to which the new particle is added.
Returns
whether PDG id exists in ParticleType table.

Definition at line 792 of file processstring.h.

793  {
794  const std::string s = std::to_string(pdgid);
795  PdgCode pythia_code(s);
796  ParticleData new_particle(ParticleType::find(pythia_code));
797  new_particle.set_4momentum(momentum);
798  intermediate_particles.push_back(new_particle);
799  return true;
800  }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ convert_KaonLS()

static void smash::StringProcess::convert_KaonLS ( int &  pythia_id)
inlinestatic

convert Kaon-L or Kaon-S into K0 or Anti-K0

Parameters
[out]pythia_idis PDG id to be converted.

Definition at line 806 of file processstring.h.

806  {
807  if (pythia_id == 310 || pythia_id == 130) {
808  pythia_id = (random::uniform_int(0, 1) == 0) ? 311 : -311;
809  }
810  }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ quarks_from_diquark()

void smash::StringProcess::quarks_from_diquark ( int  diquark,
int &  q1,
int &  q2,
int &  deg_spin 
)
static

find two quarks from a diquark.

Order does not matter.

Parameters
[in]diquarkPDG id of diquark
[out]q1PDG id of quark 1
[out]q2PDG id of quark 2
[out]deg_spinspin degeneracy

Definition at line 1671 of file processstring.cc.

1672  {
1673  // The 4-digit pdg id should be diquark.
1674  assert((std::abs(diquark) > 1000) && (std::abs(diquark) < 5510) &&
1675  (std::abs(diquark) % 100 < 10));
1676 
1677  // The fourth digit corresponds to the spin degeneracy.
1678  deg_spin = std::abs(diquark) % 10;
1679  // Diquark (anti-diquark) is decomposed into two quarks (antiquarks).
1680  const int sign_anti = diquark > 0 ? 1 : -1;
1681 
1682  // Obtain two quarks (or antiquarks) from the first and second digit.
1683  q1 = sign_anti * (std::abs(diquark) - (std::abs(diquark) % 1000)) / 1000;
1684  q2 = sign_anti * (std::abs(diquark) % 1000 - deg_spin) / 100;
1685 }
Here is the caller graph for this function:

◆ diquark_from_quarks()

int smash::StringProcess::diquark_from_quarks ( int  q1,
int  q2 
)
static

Construct diquark from two quarks.

Order does not matter.

Parameters
[in]q1PDG code of quark 1
[in]q2PDG code of quark 2
Returns
PDG code of diquark composed of q1 and q2

Definition at line 1687 of file processstring.cc.

1687  {
1688  assert((q1 > 0 && q2 > 0) || (q1 < 0 && q2 < 0));
1689  if (std::abs(q1) < std::abs(q2)) {
1690  std::swap(q1, q2);
1691  }
1692  int diquark = std::abs(q1 * 1000 + q2 * 100);
1693  /* Adding spin degeneracy = 2S+1. For identical quarks spin cannot be 0
1694  * because of Pauli exclusion principle, so spin 1 is assumed. Otherwise
1695  * S = 0 with probability 1/4 and S = 1 with probability 3/4. */
1696  diquark += (q1 != q2 && random::uniform_int(0, 3) == 0) ? 1 : 3;
1697  return (q1 < 0) ? -diquark : diquark;
1698 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ make_string_ends()

void smash::StringProcess::make_string_ends ( const PdgCode pdgcode_in,
int &  idq1,
int &  idq2,
double  xi 
)
static

make a random selection to determine partonic contents at the string ends.

Parameters
[in]pdgcode_inis PdgCode of hadron which transforms into a string.
[out]idq1is PDG id of quark or anti-diquark.
[out]idq2is PDG id of anti-quark or diquark.
[in]xiprobability to split a nucleon into the quark it has only once and a diquark of another flavour.

Definition at line 1700 of file processstring.cc.

1701  {
1702  std::array<int, 3> quarks = pdg.quark_content();
1703  if (pdg.is_nucleon()) {
1704  // protons and neutrons treated seperately since single quarks is at a
1705  // different position in the PDG code
1706  if (pdg.charge() == 0) { // (anti)neutron
1707  if (random::uniform(0., 1.) < xi) {
1708  idq1 = quarks[0];
1709  idq2 = diquark_from_quarks(quarks[1], quarks[2]);
1710  } else {
1711  idq1 = quarks[1];
1712  idq2 = diquark_from_quarks(quarks[0], quarks[2]);
1713  }
1714  } else { // (anti)proton
1715  if (random::uniform(0., 1.) < xi) {
1716  idq1 = quarks[2];
1717  idq2 = diquark_from_quarks(quarks[0], quarks[1]);
1718  } else {
1719  idq1 = quarks[0];
1720  idq2 = diquark_from_quarks(quarks[1], quarks[2]);
1721  }
1722  }
1723  } else {
1724  if (pdg.is_meson()) {
1725  idq1 = quarks[1];
1726  idq2 = quarks[2];
1727  /* Some mesons with PDG id 11X are actually mixed state of uubar and
1728  * ddbar. have a random selection whether we have uubar or ddbar in this
1729  * case. */
1730  if (idq1 == 1 && idq2 == -1 && random::uniform_int(0, 1) == 0) {
1731  idq1 = 2;
1732  idq2 = -2;
1733  }
1734  } else {
1735  assert(pdg.is_baryon());
1736  // Get random quark to position 0
1737  std::swap(quarks[random::uniform_int(0, 2)], quarks[0]);
1738  idq1 = quarks[0];
1739  idq2 = diquark_from_quarks(quarks[1], quarks[2]);
1740  }
1741  }
1742  // Fulfil the convention: idq1 should be quark or anti-diquark
1743  if (idq1 < 0) {
1744  std::swap(idq1, idq2);
1745  }
1746 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_Vec4()

static Pythia8::Vec4 smash::StringProcess::set_Vec4 ( double  energy,
const ThreeVector mom 
)
inlinestatic

Easy setter of Pythia Vec4 from SMASH.

Parameters
[in]energytime component
[in]momspatial three-vector
Returns
Pythia Vec4 from energy and ThreeVector

Definition at line 844 of file processstring.h.

844  {
845  return Pythia8::Vec4(mom.x1(), mom.x2(), mom.x3(), energy);
846  }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ reorient()

static FourVector smash::StringProcess::reorient ( Pythia8::Particle &  particle,
std::array< ThreeVector, 3 > &  evec_basis 
)
inlinestatic

compute the four-momentum properly oriented in the lab frame.

While PYTHIA assumes that the collision axis is in z-direction, this is not necessarly the case in SMASH.

Parameters
[in]particleparticle object from PYTHIA event generation where z-axis is set to be the collision axis
[in]evec_basisthree basis vectors in the lab frame evec_basis[0] is unit vector in the collision axis and other two span the transverse plane
Returns
four-momentum of particle in the lab frame

Definition at line 859 of file processstring.h.

860  {
861  ThreeVector three_momentum = evec_basis[0] * particle.pz() +
862  evec_basis[1] * particle.px() +
863  evec_basis[2] * particle.py();
864  return FourVector(particle.e(), three_momentum);
865  }
Here is the caller graph for this function:

◆ fragment_string()

int smash::StringProcess::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.2 Andersson:1983ia [2], Sjostrand:2014zea [41].

Parameters
[in]idq1PDG id of quark or anti-diquark (carrying color index).
[in]idq2PDG id of diquark or anti-quark (carrying anti-color index).
[in]mStringthe string mass. [GeV]
[out]evecLongunit 3-vector specifying the direction of diquark or anti-diquark.
[in]flip_string_endsis whether or not we randomly switch string ends.
[in]separate_fragment_baryonis whether fragment leading baryon (or anti-baryon) with separate fragmentation function.
[out]intermediate_particleslist of fragmented particles
Returns
number of hadrons fragmented out of string.
Exceptions
std::runtime_errorif string mass is lower than threshold set by PYTHIA

Definition at line 1748 of file processstring.cc.

1751  {
1752  pythia_hadron_->event.reset();
1753  intermediate_particles.clear();
1754 
1755  logg[LPythia].debug("initial quark content for fragment_string : ", idq1,
1756  ", ", idq2);
1757  logg[LPythia].debug("initial string mass (GeV) for fragment_string : ",
1758  mString);
1759  // PDG id of quark constituents of string ends
1760  std::array<int, 2> idqIn;
1761  idqIn[0] = idq1;
1762  idqIn[1] = idq2;
1763 
1764  int bstring = 0;
1765  // constituent masses of the string
1766  std::array<double, 2> m_const;
1767 
1768  for (int i = 0; i < 2; i++) {
1769  // evaluate total baryon number of the string times 3
1770  bstring += pythia_hadron_->particleData.baryonNumberType(idqIn[i]);
1771 
1772  m_const[i] = pythia_hadron_->particleData.m0(idqIn[i]);
1773  }
1774  logg[LPythia].debug("baryon number of string times 3 : ", bstring);
1775 
1776  if (flip_string_ends && random::uniform_int(0, 1) == 0) {
1777  /* in the case where we flip the string ends,
1778  * we need to flip the longitudinal unit vector itself
1779  * since it is set to be direction of diquark (anti-quark)
1780  * or anti-diquark. */
1781  evecLong = -evecLong;
1782  }
1783 
1784  if (m_const[0] + m_const[1] > mString) {
1785  throw std::runtime_error("String fragmentation: m1 + m2 > mString");
1786  }
1787  Pythia8::Vec4 pSum = 0.;
1788 
1789  int number_of_fragments = 0;
1790  bool do_string_fragmentation = false;
1791 
1792  /* lightcone momenta p^+ and p^- of the string
1793  * p^{\pm} is defined as (E \pm p_{longitudinal}) / sqrts{2}. */
1794  double ppos_string_new, pneg_string_new;
1795  /* transverse momentum (and magnitude) acquired
1796  * by the the string to be fragmented */
1797  double QTrx_string_new, QTry_string_new, QTrn_string_new;
1798  // transverse mass of the string to be fragmented
1799  double mTrn_string_new;
1800  // mass of the string to be fragmented
1801  double mass_string_new;
1802 
1803  /* Transverse momentum to be added to the most forward hadron
1804  * from PYTHIA fragmentation */
1805  double QTrx_add_pos, QTry_add_pos;
1806  /* Transverse momentum to be added to the most backward hadron
1807  * from PYTHIA fragmentation */
1808  double QTrx_add_neg, QTry_add_neg;
1809 
1810  /* Set those transverse momenta to be zero.
1811  * This is the case when we solely rely on the PYTHIA fragmentation
1812  * procedure without separate fragmentation function.
1813  * In the case of separate fragmentation function for the leading baryon,
1814  * appropriate values will be assigned later. */
1815  QTrx_add_pos = 0.;
1816  QTry_add_pos = 0.;
1817  QTrx_add_neg = 0.;
1818  QTry_add_neg = 0.;
1819 
1820  std::array<ThreeVector, 3> evec_basis;
1821  make_orthonormal_basis(evecLong, evec_basis);
1822 
1823  if (separate_fragment_baryon && (std::abs(bstring) == 3) &&
1824  (mString > m_const[0] + m_const[1] + 1.)) {
1825  /* A separate fragmentation function will be used to the leading baryon,
1826  * if we have a baryonic string and the corresponding option is turned on.
1827  */
1828  int n_frag_prior;
1829  /* PDG id of fragmented hadrons
1830  * before switching to the PYTHIA fragmentation */
1831  std::vector<int> pdgid_frag_prior;
1832  /* four-momenta of fragmented hadrons
1833  * before switching to the PYTHIA fragmentation */
1834  std::vector<FourVector> momentum_frag_prior;
1835 
1836  // Transverse momentum px of the forward end of the string
1837  double QTrx_string_pos;
1838  // Transverse momentum px of the backward end of the string
1839  double QTrx_string_neg;
1840  // Transverse momentum py of the forward end of the string
1841  double QTry_string_pos;
1842  // Transverse momentum py of the backward end of the string
1843  double QTry_string_neg;
1844  /* Absolute value of the transverse momentum of
1845  * the forward end of the string */
1846  double QTrn_string_pos;
1847  /* Absolute value of the transverse momentum of
1848  * the backward end of the string */
1849  double QTrn_string_neg;
1850 
1851  std::array<double, 2> m_trans;
1852 
1853  // How many times we try to fragment leading baryon.
1854  const int niter_max = 10000;
1855  bool found_leading_baryon = false;
1856  for (int iiter = 0; iiter < niter_max; iiter++) {
1857  n_frag_prior = 0;
1858  pdgid_frag_prior.clear();
1859  momentum_frag_prior.clear();
1860  int n_frag = 0;
1861  std::vector<int> pdgid_frag;
1862  std::vector<FourVector> momentum_frag;
1863  // The original string is aligned in the logitudinal direction.
1864  ppos_string_new = mString * M_SQRT1_2;
1865  pneg_string_new = mString * M_SQRT1_2;
1866  // There is no transverse momentum at the original string ends.
1867  QTrx_string_pos = 0.;
1868  QTrx_string_neg = 0.;
1869  QTrx_string_new = 0.;
1870  QTry_string_pos = 0.;
1871  QTry_string_neg = 0.;
1872  QTry_string_new = 0.;
1873  // Constituent flavor at the forward (diquark) end of the string
1874  Pythia8::FlavContainer flav_string_pos =
1875  bstring > 0 ? Pythia8::FlavContainer(idq2)
1876  : Pythia8::FlavContainer(idq1);
1877  // Constituent flavor at the backward (quark) end of the string
1878  Pythia8::FlavContainer flav_string_neg =
1879  bstring > 0 ? Pythia8::FlavContainer(idq1)
1880  : Pythia8::FlavContainer(idq2);
1881  // Whether the first baryon from the forward end is fragmented
1882  bool found_forward_baryon = false;
1883  // Whether the first hadron from the forward end is fragmented
1884  bool done_forward_end = false;
1885  /* Whether energy of the string is depleted and the string
1886  * breaks into final two hadrons. */
1887  bool energy_used_up = false;
1888  while (!found_forward_baryon && !energy_used_up) {
1889  /* Keep fragmenting hadrons until
1890  * the first baryon is fragmented from the forward (diquark) end or
1891  * energy of the string is used up. */
1892  // Randomly select the string end from which the hadron is fragmented.
1893  bool from_forward = random::uniform_int(0, 1) == 0;
1894  /* The separate fragmentation function for the leading baryon kicks in
1895  * only if the first fragmented hadron from the forward (diquark) end
1896  * is a baryon. */
1897  n_frag = fragment_off_hadron(
1898  from_forward,
1899  separate_fragment_baryon && from_forward && !done_forward_end,
1900  evec_basis, ppos_string_new, pneg_string_new, QTrx_string_pos,
1901  QTrx_string_neg, QTry_string_pos, QTry_string_neg, flav_string_pos,
1902  flav_string_neg, pdgid_frag, momentum_frag);
1903  if (n_frag == 0) {
1904  /* If it fails to fragment hadron, start over from
1905  * the initial (baryonic) string configuration. */
1906  break;
1907  } else {
1908  QTrx_string_new = QTrx_string_pos + QTrx_string_neg;
1909  QTry_string_new = QTry_string_pos + QTry_string_neg;
1910  /* Quark (antiquark) constituents of the remaining string are
1911  * different from those of the original string.
1912  * Therefore, the constituent masses have to be updated. */
1913  idqIn[0] = bstring > 0 ? flav_string_neg.id : flav_string_pos.id;
1914  idqIn[1] = bstring > 0 ? flav_string_pos.id : flav_string_neg.id;
1915  for (int i = 0; i < 2; i++) {
1916  m_const[i] = pythia_hadron_->particleData.m0(idqIn[i]);
1917  }
1918  QTrn_string_pos = std::sqrt(QTrx_string_pos * QTrx_string_pos +
1919  QTry_string_pos * QTry_string_pos);
1920  QTrn_string_neg = std::sqrt(QTrx_string_neg * QTrx_string_neg +
1921  QTry_string_neg * QTry_string_neg);
1922  if (bstring > 0) { // in the case of baryonic string
1923  /* Quark is coming from the newly produced backward qqbar pair
1924  * and therefore has transverse momentum, which is opposite to
1925  * that of the fragmented (backward) meson. */
1926  m_trans[0] = std::sqrt(m_const[0] * m_const[0] +
1927  QTrn_string_neg * QTrn_string_neg);
1928  /* Antiquark is coming from the newly produced forward qqbar pair
1929  * and therefore has transverse momentum, which is opposite to
1930  * that of the fragmented (leading) baryon. */
1931  m_trans[1] = std::sqrt(m_const[1] * m_const[1] +
1932  QTrn_string_pos * QTrn_string_pos);
1933  } else { // in the case of anti-baryonic string
1934  /* Quark is coming from the newly produced forward qqbar pair
1935  * and therefore has transverse momentum, which is opposite to
1936  * that of the fragmented (leading) antibaryon. */
1937  m_trans[0] = std::sqrt(m_const[0] * m_const[0] +
1938  QTrn_string_pos * QTrn_string_pos);
1939  /* Antiquark is coming from the newly produced backward qqbar pair
1940  * and therefore has transverse momentum, which is opposite to
1941  * that of the fragmented (backward) meson. */
1942  m_trans[1] = std::sqrt(m_const[1] * m_const[1] +
1943  QTrn_string_neg * QTrn_string_neg);
1944  }
1945  done_forward_end = done_forward_end || from_forward;
1946  found_forward_baryon =
1947  found_forward_baryon ||
1948  (from_forward &&
1949  pythia_hadron_->particleData.isBaryon(pdgid_frag[0]));
1950  }
1951  if (n_frag == 2) {
1952  energy_used_up = true;
1953  }
1954  /* Add PDG id and four-momenta of fragmented hadrons
1955  * to the list if fragmentation is successful. */
1956  n_frag_prior += n_frag;
1957  for (int i_frag = 0; i_frag < n_frag; i_frag++) {
1958  pdgid_frag_prior.push_back(pdgid_frag[i_frag]);
1959  momentum_frag_prior.push_back(momentum_frag[i_frag]);
1960  }
1961  }
1962  if (n_frag == 0) {
1963  continue;
1964  } else {
1965  if (n_frag == 1) {
1966  // Compute transverse mass and momentum of the remaining string.
1967  double mTsqr_string = 2. * ppos_string_new * pneg_string_new;
1968  mTrn_string_new = std::sqrt(mTsqr_string);
1969  QTrn_string_new = std::sqrt(QTrx_string_new * QTrx_string_new +
1970  QTry_string_new * QTry_string_new);
1971  if (mTrn_string_new < QTrn_string_new) {
1972  /* If transverse mass is lower than transverse momentum,
1973  * start over. */
1974  found_leading_baryon = false;
1975  } else {
1976  // Compute mass of the remaining string.
1977  mass_string_new =
1978  std::sqrt(mTsqr_string - QTrn_string_new * QTrn_string_new);
1979  /* Proceed only if the string mass is large enough to call
1980  * PYTHIA fragmentation routine.
1981  * Otherwise, start over. */
1982  if (mass_string_new > m_const[0] + m_const[1]) {
1983  do_string_fragmentation = true;
1984  found_leading_baryon = true;
1985  QTrx_add_pos = QTrx_string_pos;
1986  QTry_add_pos = QTry_string_pos;
1987  QTrx_add_neg = QTrx_string_neg;
1988  QTry_add_neg = QTry_string_neg;
1989  } else {
1990  found_leading_baryon = false;
1991  }
1992  }
1993  } else if (n_frag == 2) {
1994  /* If the string ended up breaking into final two hadrons,
1995  * there is no need to perform PYTHIA fragmentation. */
1996  do_string_fragmentation = false;
1997  found_leading_baryon = true;
1998  }
1999  }
2000 
2001  if (found_leading_baryon) {
2002  break;
2003  }
2004  }
2005  if (found_leading_baryon) {
2006  /* If the kinematics makes sense, add fragmented hadrons so far
2007  * to the intermediate particle list. */
2008  for (int i_frag = 0; i_frag < n_frag_prior; i_frag++) {
2009  logg[LPythia].debug("appending the the fragmented hadron ",
2010  pdgid_frag_prior[i_frag],
2011  " to the intermediate particle list.");
2012 
2013  bool found_ptype = append_intermediate_list(pdgid_frag_prior[i_frag],
2014  momentum_frag_prior[i_frag],
2015  intermediate_particles);
2016  if (!found_ptype) {
2017  logg[LPythia].error("PDG ID ", pdgid_frag_prior[i_frag],
2018  " should exist in ParticleType.");
2019  throw std::runtime_error("string fragmentation failed.");
2020  }
2021  number_of_fragments++;
2022  }
2023  } else {
2024  /* If it is not possible to find the leading baryon with appropriate
2025  * kinematics after trying many times, return failure (no hadron). */
2026  return 0;
2027  }
2028 
2029  if (do_string_fragmentation) {
2030  mTrn_string_new = std::sqrt(2. * ppos_string_new * pneg_string_new);
2031  // lightcone momentum p^+ of the quark constituents on the string ends
2032  std::array<double, 2> ppos_parton;
2033  // lightcone momentum p^- of the quark constituents on the string ends
2034  std::array<double, 2> pneg_parton;
2035 
2036  /* lightcone momenta of the string ends (quark and antiquark)
2037  * First, obtain ppos_parton[0] and ppos_parton[1]
2038  * (p^+ of quark and antiquark) by solving the following equations.
2039  * ppos_string_new = ppos_parton[0] + ppos_parton[1]
2040  * pneg_string_new = 0.5 * m_trans[0] * m_trans[0] / ppos_parton[0] +
2041  * 0.5 * m_trans[1] * m_trans[1] / ppos_parton[1] */
2042  const double pb_const =
2043  (mTrn_string_new * mTrn_string_new + m_trans[0] * m_trans[0] -
2044  m_trans[1] * m_trans[1]) /
2045  (4. * pneg_string_new);
2046  const double pc_const =
2047  0.5 * m_trans[0] * m_trans[0] * ppos_string_new / pneg_string_new;
2048  ppos_parton[0] = pb_const + (bstring > 0 ? -1. : 1.) *
2049  std::sqrt(pb_const * pb_const - pc_const);
2050  ppos_parton[1] = ppos_string_new - ppos_parton[0];
2051  /* Then, compute pneg_parton[0] and pneg_parton[1]
2052  * (p^- of quark and antiquark) from the dispersion relation.
2053  * 2 p^+ p^- = m_transverse^2 */
2054  for (int i = 0; i < 2; i++) {
2055  pneg_parton[i] = 0.5 * m_trans[i] * m_trans[i] / ppos_parton[i];
2056  }
2057 
2058  const int status = 1;
2059  int color, anticolor;
2060  ThreeVector three_mom;
2061  ThreeVector transverse_mom;
2062  Pythia8::Vec4 pquark;
2063 
2064  // quark end of the remaining (mesonic) string
2065  color = 1;
2066  anticolor = 0;
2067  /* In the case of baryonic string,
2068  * Quark is coming from the backward end of the remaining string.
2069  * Transverse momentum of the backward end is subtracted
2070  * at this point to keep the remaining string aligned in
2071  * the original longitudinal direction.
2072  * It will be added to the most backward hadron from
2073  * PYTHIA fragmentation.
2074  * In the case of anti-baryonic string,
2075  * Quark is coming from the forward end of the remaining string.
2076  * Transverse momentum of the forward end is subtracted
2077  * at this point to keep the remaining string aligned in
2078  * the original longitudinal direction.
2079  * It will be added to the most forward hadron from
2080  * PYTHIA fragmentation. */
2081  transverse_mom =
2082  bstring > 0 ? evec_basis[1] * (QTrx_string_neg - QTrx_add_neg) +
2083  evec_basis[2] * (QTry_string_neg - QTry_add_neg)
2084  : evec_basis[1] * (QTrx_string_pos - QTrx_add_pos) +
2085  evec_basis[2] * (QTry_string_pos - QTry_add_pos);
2086  three_mom =
2087  evec_basis[0] * (ppos_parton[0] - pneg_parton[0]) * M_SQRT1_2 +
2088  transverse_mom;
2089  const double E_quark =
2090  std::sqrt(m_const[0] * m_const[0] + three_mom.sqr());
2091  pquark = set_Vec4(E_quark, three_mom);
2092  pSum += pquark;
2093  pythia_hadron_->event.append(idqIn[0], status, color, anticolor, pquark,
2094  m_const[0]);
2095 
2096  // antiquark end of the remaining (mesonic) string
2097  color = 0;
2098  anticolor = 1;
2099  /* In the case of baryonic string,
2100  * Antiquark is coming from the forward end of the remaining string.
2101  * Transverse momentum of the forward end is subtracted
2102  * at this point to keep the remaining string aligned in
2103  * the original longitudinal direction.
2104  * It will be added to the most forward hadron from
2105  * PYTHIA fragmentation.
2106  * In the case of anti-baryonic string,
2107  * Antiquark is coming from the backward end of the remaining string.
2108  * Transverse momentum of the backward end is subtracted
2109  * at this point to keep the remaining string aligned in
2110  * the original longitudinal direction.
2111  * It will be added to the most backward hadron from
2112  * PYTHIA fragmentation. */
2113  transverse_mom =
2114  bstring > 0 ? evec_basis[1] * (QTrx_string_pos - QTrx_add_pos) +
2115  evec_basis[2] * (QTry_string_pos - QTry_add_pos)
2116  : evec_basis[1] * (QTrx_string_neg - QTrx_add_neg) +
2117  evec_basis[2] * (QTry_string_neg - QTry_add_neg);
2118  three_mom =
2119  evec_basis[0] * (ppos_parton[1] - pneg_parton[1]) * M_SQRT1_2 +
2120  transverse_mom;
2121  const double E_antiq =
2122  std::sqrt(m_const[1] * m_const[1] + three_mom.sqr());
2123  pquark = set_Vec4(E_antiq, three_mom);
2124  pSum += pquark;
2125  pythia_hadron_->event.append(idqIn[1], status, color, anticolor, pquark,
2126  m_const[1]);
2127  }
2128  } else {
2129  do_string_fragmentation = true;
2130 
2131  ppos_string_new = mString * M_SQRT1_2;
2132  pneg_string_new = mString * M_SQRT1_2;
2133  QTrx_string_new = 0.;
2134  QTry_string_new = 0.;
2135  QTrn_string_new = 0.;
2136  mTrn_string_new = mString;
2137  mass_string_new = mString;
2138 
2139  /* diquark (anti-quark) with PDG id idq2 is going in the direction of
2140  * evecLong.
2141  * quark with PDG id idq1 is going in the direction opposite to evecLong. */
2142  double sign_direction = 1.;
2143  if (bstring == -3) { // anti-baryonic string
2144  /* anti-diquark with PDG id idq1 is going in the direction of evecLong.
2145  * anti-quark with PDG id idq2 is going in the direction
2146  * opposite to evecLong. */
2147  sign_direction = -1;
2148  }
2149 
2150  // evaluate momenta of quarks
2151  const double pCMquark = pCM(mString, m_const[0], m_const[1]);
2152  const double E1 = std::sqrt(m_const[0] * m_const[0] + pCMquark * pCMquark);
2153  const double E2 = std::sqrt(m_const[1] * m_const[1] + pCMquark * pCMquark);
2154 
2155  ThreeVector direction = sign_direction * evecLong;
2156 
2157  // For status and (anti)color see \iref{Sjostrand:2007gs}.
2158  const int status1 = 1, color1 = 1, anticolor1 = 0;
2159  Pythia8::Vec4 pquark = set_Vec4(E1, -direction * pCMquark);
2160  pSum += pquark;
2161  pythia_hadron_->event.append(idqIn[0], status1, color1, anticolor1, pquark,
2162  m_const[0]);
2163 
2164  const int status2 = 1, color2 = 0, anticolor2 = 1;
2165  pquark = set_Vec4(E2, direction * pCMquark);
2166  pSum += pquark;
2167  pythia_hadron_->event.append(idqIn[1], status2, color2, anticolor2, pquark,
2168  m_const[1]);
2169  }
2170 
2171  if (do_string_fragmentation) {
2172  logg[LPythia].debug("fragmenting a string with ", idqIn[0], ", ", idqIn[1]);
2173  // implement PYTHIA fragmentation
2174  pythia_hadron_->event[0].p(pSum);
2175  pythia_hadron_->event[0].m(pSum.mCalc());
2176  bool successful_hadronization = pythia_hadron_->next();
2177  if (!successful_hadronization) {
2178  return 0;
2179  }
2180 
2181  /* Add transverse momenta of string ends to the most forward and
2182  * backward hadrons from PYTHIA fragmentation. */
2183  bool successful_kinematics = remake_kinematics_fragments(
2184  pythia_hadron_->event, evec_basis, ppos_string_new, pneg_string_new,
2185  QTrx_string_new, QTry_string_new, QTrx_add_pos, QTry_add_pos,
2186  QTrx_add_neg, QTry_add_neg);
2187  if (!successful_kinematics) {
2188  return 0;
2189  }
2190 
2191  for (int ipyth = 0; ipyth < pythia_hadron_->event.size(); ipyth++) {
2192  if (!pythia_hadron_->event[ipyth].isFinal()) {
2193  continue;
2194  }
2195  int pythia_id = pythia_hadron_->event[ipyth].id();
2196  /* K_short and K_long need are converted to K0
2197  * since SMASH only knows K0 */
2198  convert_KaonLS(pythia_id);
2199  FourVector momentum(
2200  pythia_hadron_->event[ipyth].e(), pythia_hadron_->event[ipyth].px(),
2201  pythia_hadron_->event[ipyth].py(), pythia_hadron_->event[ipyth].pz());
2202  logg[LPythia].debug("appending the fragmented hadron ", pythia_id,
2203  " to the intermediate particle list.");
2204  bool found_ptype =
2205  append_intermediate_list(pythia_id, momentum, intermediate_particles);
2206  if (!found_ptype) {
2207  logg[LPythia].warn("PDG ID ", pythia_id,
2208  " does not exist in ParticleType - start over.");
2209  intermediate_particles.clear();
2210  return 0;
2211  }
2212 
2213  number_of_fragments++;
2214  }
2215  }
2216  return number_of_fragments;
2217 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ fragment_off_hadron()

int smash::StringProcess::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 the consituent masses).

Otherwise the entire string breaks down into (final) two hadrons.

Parameters
[in]from_forwardwhether a hadron is fragmented from the forward end of the string
[in]separate_fragment_baryonwhether a separate fragmentation function is used for the leading baryon from the diquark end of string.
[in]evec_basisthree orthonormal basis vectors of which evec_basis[0] is in the longitudinal direction while evec_basis[1] and evec_basis[2] span the transverse plane.
[out]ppos_stringlightcone momentum p^+ of the string. This will be changed according to that of the remaining string.
[out]pneg_stringlightcone momentum p^- of the string. This will be changed according to that of the remaining string.
[out]QTrx_string_postransverse momentum px carried by the forward end of the string. This will be changed according to that of the remaining string.
[out]QTrx_string_negtransverse momentum px carried by the backward end of the string. This will be changed according to that of the remaining string.
[out]QTry_string_postransverse momentum py carried by the forward end of the string. This will be changed according to that of the remaining string.
[out]QTry_string_negtransverse momentum py carried by the backward end of the string. This will be changed according to that of the remaining string.
[out]flav_string_posconstituent flavor at the forward end of the string. This will be changed according to that of the remaining string.
[out]flav_string_negconstituent flavor at the backward end of the string. This will be changed according to that of the remaining string.
[out]pdgid_fragPDG id of fragmented hadron(s)
[out]momentum_fragfour-momenta of fragmented hadrons(s)
Returns
number of fragmented hadron(s). It can be 1 or 2 depending on the string mass. If it fails to fragment, returns 0.

Definition at line 2219 of file processstring.cc.

2226  {
2227  /* How many times we try to find flavor of qqbar pair and corresponding
2228  * hadronic species */
2229  const int n_try = 10;
2230  pdgid_frag.clear();
2231  momentum_frag.clear();
2232 
2233  if (ppos_string < 0. || pneg_string < 0.) {
2234  throw std::runtime_error("string has a negative lightcone momentum.");
2235  }
2236  double mTsqr_string = 2. * ppos_string * pneg_string;
2237  // Transverse mass of the original string
2238  double mTrn_string = std::sqrt(mTsqr_string);
2239  // Total transverse momentum of the original string
2240  double QTrx_string_tot = QTrx_string_pos + QTrx_string_neg;
2241  double QTry_string_tot = QTry_string_pos + QTry_string_neg;
2242  double QTsqr_string_tot = std::fabs(QTrx_string_tot * QTrx_string_tot) +
2243  std::fabs(QTry_string_tot * QTry_string_tot);
2244  double QTrn_string_tot = std::sqrt(QTsqr_string_tot);
2245  if (mTrn_string < QTrn_string_tot) {
2246  return 0;
2247  }
2248  // Mass of the original string
2249  double mass_string = std::sqrt(mTsqr_string - QTsqr_string_tot);
2250  logg[LPythia].debug(" Fragment off one hadron from a string ( ",
2251  flav_string_pos.id, " , ", flav_string_neg.id,
2252  " ) with mass ", mass_string, " GeV.");
2253 
2254  // Take relevant parameters from PYTHIA.
2255  const double sigma_qt_frag = pythia_hadron_->parm("StringPT:sigma");
2256  const double stop_string_mass =
2257  pythia_hadron_->parm("StringFragmentation:stopMass");
2258  const double stop_string_smear =
2259  pythia_hadron_->parm("StringFragmentation:stopSmear");
2260 
2261  // Enhance the width of transverse momentum with certain probability
2262  const double prob_enhance_qt =
2263  pythia_hadron_->parm("StringPT:enhancedFraction");
2264  double fac_enhance_qt;
2265  if (random::uniform(0., 1.) < prob_enhance_qt) {
2266  fac_enhance_qt = pythia_hadron_->parm("StringPT:enhancedWidth");
2267  } else {
2268  fac_enhance_qt = 1.;
2269  }
2270 
2271  /* Sample the transverse momentum of newly created quark-antiquark
2272  * (or diquark-antidiquark) pair.
2273  * Note that one constituent carries QT_new while -QT_new is carried by
2274  * another.
2275  * The former one is taken by the (first) fragmented hadron and
2276  * the later one will be assigned to the remaining string or
2277  * taken by the second fragmented hadron. */
2278  double QTrx_new =
2279  random::normal(0., fac_enhance_qt * sigma_qt_frag * M_SQRT1_2);
2280  double QTry_new =
2281  random::normal(0., fac_enhance_qt * sigma_qt_frag * M_SQRT1_2);
2282  logg[LPythia].debug(" Transverse momentum (", QTrx_new, ", ", QTry_new,
2283  ") GeV selected for the new qqbar pair.");
2284 
2285  /* Determine the transverse momentum of the (first) fragmented hadron.
2286  * Transverse momentum of hadron =
2287  * QT_string (of the string end) +
2288  * QT_new (of one of the quark-antiquark pair).
2289  * If the first hadron is fragmented from the forward (backward) end
2290  * of a string, then transverse momentum carried by the forward (backward)
2291  * end is taken. */
2292  double QTrx_had_1st =
2293  from_forward ? QTrx_string_pos + QTrx_new : QTrx_string_neg + QTrx_new;
2294  double QTry_had_1st =
2295  from_forward ? QTry_string_pos + QTry_new : QTry_string_neg + QTry_new;
2296  double QTrn_had_1st =
2297  std::sqrt(QTrx_had_1st * QTrx_had_1st + QTry_had_1st * QTry_had_1st);
2298 
2299  // PDG id of the (first) fragmented hadron
2300  int pdgid_had_1st = 0;
2301  // Mass of the (first) fragmented hadron
2302  double mass_had_1st = 0.;
2303  /* Constituent flavor of the original string end,
2304  * at which the (first) hadron is fragmented. */
2305  Pythia8::FlavContainer flav_old =
2306  from_forward ? flav_string_pos : flav_string_neg;
2307  /* Constituent flavor of newly created quark-antiquark pair,
2308  * which is taken by the (first) fragmented hadron.
2309  * Antiparticle of this flavor will be assigned to the remaining string,
2310  * or taken by the second fragmented hadron. */
2311  Pythia8::FlavContainer flav_new = Pythia8::FlavContainer(0);
2312  /* Sample flavor of the quark-antiquark (or diquark-antidiquark) pair
2313  * and combine with that of the original string end to find the hadronic
2314  * species. */
2315  for (int i_try = 0; i_try < n_try; i_try++) {
2316  // Sample the new flavor.
2317  flav_new = pythia_stringflav_.pick(flav_old);
2318  // Combine to get the PDG id of hadron.
2319  pdgid_had_1st = pythia_stringflav_.combine(flav_old, flav_new);
2320  if (pdgid_had_1st != 0) {
2321  // If the PDG id is found, determine mass.
2322  mass_had_1st = pythia_hadron_->particleData.mSel(pdgid_had_1st);
2323  logg[LPythia].debug(" number of tries of flavor selection : ",
2324  i_try + 1, " in StringProcess::fragment_off_hadron.");
2325  break;
2326  }
2327  }
2328  if (pdgid_had_1st == 0) {
2329  return 0;
2330  }
2331  logg[LPythia].debug(" New flavor ", flav_new.id,
2332  " selected for the string end with ", flav_old.id);
2333  logg[LPythia].debug(" PDG id ", pdgid_had_1st,
2334  " selected for the (first) fragmented hadron.");
2335  bool had_1st_baryon = pythia_hadron_->particleData.isBaryon(pdgid_had_1st);
2336  // Transverse mass of the (first) fragmented hadron
2337  double mTrn_had_1st =
2338  std::sqrt(mass_had_1st * mass_had_1st + QTrn_had_1st * QTrn_had_1st);
2339  logg[LPythia].debug(" Transverse momentum (", QTrx_had_1st, ", ",
2340  QTry_had_1st,
2341  ") GeV selected for the (first) fragmented hadron.");
2342 
2343  /* Compute the mass threshold to continue string fragmentation.
2344  * This formula is taken from StringFragmentation::energyUsedUp
2345  * in StringFragmentation.cc of PYTHIA 8. */
2346  const double mass_min_to_continue =
2347  (stop_string_mass + pythia_hadron_->particleData.m0(flav_new.id) +
2348  pythia_hadron_->particleData.m0(flav_string_pos.id) +
2349  pythia_hadron_->particleData.m0(flav_string_neg.id)) *
2350  (1. + (2. * random::uniform(0., 1.) - 1.) * stop_string_smear);
2351  /* If the string mass is lower than that threshold,
2352  * the string breaks into the last two hadrons. */
2353  bool string_into_final_two = mass_string < mass_min_to_continue;
2354  if (string_into_final_two) {
2355  logg[LPythia].debug(" The string mass is below the mass threshold ",
2356  mass_min_to_continue,
2357  " GeV : finishing with two hadrons.");
2358  }
2359 
2360  // Lightcone momentum of the (first) fragmented hadron
2361  double ppos_had_1st = 0.;
2362  double pneg_had_1st = 0.;
2363 
2364  /* Whether the string end, at which the (first) hadron is fragmented,
2365  * had a diquark or antidiquark */
2366  bool from_diquark_end =
2367  from_forward ? pythia_hadron_->particleData.isDiquark(flav_string_pos.id)
2368  : pythia_hadron_->particleData.isDiquark(flav_string_neg.id);
2369  // Whether the forward end of the string has a diquark
2370  bool has_diquark_pos =
2371  pythia_hadron_->particleData.isDiquark(flav_string_pos.id);
2372 
2373  int n_frag = 0;
2374  if (string_into_final_two) {
2375  /* In the case of a string breaking into the last two hadrons,
2376  * we determine species, mass and four-momentum of the second hadron. */
2377  // PDG id of the second fragmented hadron
2378  int pdgid_had_2nd = 0.;
2379  // Mass of the second fragmented hadron
2380  double mass_had_2nd = 0.;
2381  /* Constituent flavor of newly created quark-antiquark pair,
2382  * which is taken by the second fragmented hadron. */
2383  Pythia8::FlavContainer flav_new2 = Pythia8::FlavContainer(0);
2384  flav_new2.anti(flav_new);
2385  /* Getting a hadron from diquark and antidiquark does not always work.
2386  * So, if this is the case, start over. */
2387  if (pythia_hadron_->particleData.isDiquark(flav_string_neg.id) &&
2388  pythia_hadron_->particleData.isDiquark(flav_new2.id) && from_forward) {
2389  return 0;
2390  }
2391  if (pythia_hadron_->particleData.isDiquark(flav_string_pos.id) &&
2392  pythia_hadron_->particleData.isDiquark(flav_new2.id) && !from_forward) {
2393  return 0;
2394  }
2395  for (int i_try = 0; i_try < n_try; i_try++) {
2396  // Combine to get the PDG id of the second hadron.
2397  pdgid_had_2nd =
2398  from_forward ? pythia_stringflav_.combine(flav_string_neg, flav_new2)
2399  : pythia_stringflav_.combine(flav_string_pos, flav_new2);
2400  if (pdgid_had_2nd != 0) {
2401  // If the PDG id is found, determine mass.
2402  mass_had_2nd = pythia_hadron_->particleData.mSel(pdgid_had_2nd);
2403  break;
2404  }
2405  }
2406  if (pdgid_had_2nd == 0) {
2407  return 0;
2408  }
2409  logg[LPythia].debug(" PDG id ", pdgid_had_2nd,
2410  " selected for the (second) fragmented hadron.");
2411  bool had_2nd_baryon = pythia_hadron_->particleData.isBaryon(pdgid_had_2nd);
2412 
2413  /* Determine transverse momentum carried by the second hadron.
2414  * If the first hadron fragmented from the forward (backward) end
2415  * of a string, transvere momentum at the backward (forward) end will
2416  * contribute.
2417  * Transverse momentum of newly created constituent
2418  * must be added as well. */
2419  double QTrx_had_2nd =
2420  from_forward ? QTrx_string_neg - QTrx_new : QTrx_string_pos - QTrx_new;
2421  double QTry_had_2nd =
2422  from_forward ? QTry_string_neg - QTry_new : QTry_string_pos - QTry_new;
2423  double QTrn_had_2nd =
2424  std::sqrt(QTrx_had_2nd * QTrx_had_2nd + QTry_had_2nd * QTry_had_2nd);
2425  double mTrn_had_2nd =
2426  std::sqrt(mass_had_2nd * mass_had_2nd + QTrn_had_2nd * QTrn_had_2nd);
2427  logg[LPythia].debug(" Transverse momentum (", QTrx_had_2nd, ", ",
2428  QTry_had_2nd,
2429  ") GeV selected for the (second) fragmented hadron.");
2430 
2431  double ppos_had_2nd = 0.;
2432  double pneg_had_2nd = 0.;
2433 
2434  /* Compute lightcone momenta of the final two hadrons.
2435  * If the fragmentation begins at the forward (backward) end of a string,
2436  * the first (second) hadron is the forward one and the second (first)
2437  * hadron is the backward one. */
2438  bool found_kinematics =
2439  from_forward
2441  separate_fragment_baryon && has_diquark_pos && had_1st_baryon,
2442  ppos_string, pneg_string, mTrn_had_1st, mTrn_had_2nd,
2443  ppos_had_1st, ppos_had_2nd, pneg_had_1st, pneg_had_2nd)
2445  separate_fragment_baryon && has_diquark_pos && had_2nd_baryon,
2446  ppos_string, pneg_string, mTrn_had_2nd, mTrn_had_1st,
2447  ppos_had_2nd, ppos_had_1st, pneg_had_2nd, pneg_had_1st);
2448  if (!found_kinematics) {
2449  return 0;
2450  }
2451 
2452  // The entire string breaks into hadrons, so there is no momentum left.
2453  ppos_string = 0.;
2454  pneg_string = 0.;
2455  QTrx_string_pos = 0.;
2456  QTry_string_pos = 0.;
2457 
2458  // Add the first hadron to the list.
2459  pdgid_frag.push_back(pdgid_had_1st);
2460  FourVector mom_had_1st = FourVector(
2461  (ppos_had_1st + pneg_had_1st) * M_SQRT1_2,
2462  evec_basis[0] * (ppos_had_1st - pneg_had_1st) * M_SQRT1_2 +
2463  evec_basis[1] * QTrx_had_1st + evec_basis[2] * QTry_had_1st);
2464  momentum_frag.push_back(mom_had_1st);
2465 
2466  // Add the second hadron to the list.
2467  pdgid_frag.push_back(pdgid_had_2nd);
2468  FourVector mom_had_2nd = FourVector(
2469  (ppos_had_2nd + pneg_had_2nd) * M_SQRT1_2,
2470  evec_basis[0] * (ppos_had_2nd - pneg_had_2nd) * M_SQRT1_2 +
2471  evec_basis[1] * QTrx_had_2nd + evec_basis[2] * QTry_had_2nd);
2472  momentum_frag.push_back(mom_had_2nd);
2473 
2474  n_frag += 2;
2475  } else {
2476  /* If the string mass is large enough (larger than the threshold),
2477  * perform the normal fragmentation.
2478  * Different sets of parameters for the LUND fragmentation function
2479  * are used, depending on whether the (first) fragmented hadrons is
2480  * the leading baryon. */
2481  double stringz_a_use, stringz_b_use;
2482  /* If the firstly fragmented hadron from the diquark end is a baryon,
2483  * it can be considered to be the leading baryon. */
2484  if (separate_fragment_baryon && from_diquark_end && had_1st_baryon) {
2485  stringz_a_use = stringz_a_leading_;
2486  stringz_b_use = stringz_b_leading_;
2487  } else {
2488  stringz_a_use = stringz_a_produce_;
2489  stringz_b_use = stringz_b_produce_;
2490  }
2491 
2492  /* Sample the lightcone momentum fraction from
2493  * the LUND fragmentation function. */
2494  double xfrac = sample_zLund(stringz_a_use, stringz_b_use, mTrn_had_1st);
2495  if (from_forward) {
2496  /* If the (first) hadron is fragmented from the forward end,
2497  * it is the lightcone momentum fraction of p^+ */
2498  ppos_had_1st = xfrac * ppos_string;
2499  pneg_had_1st = 0.5 * mTrn_had_1st * mTrn_had_1st / ppos_had_1st;
2500  if (pneg_had_1st > pneg_string) {
2501  return 0;
2502  }
2503  } else {
2504  /* If the (first) hadron is fragmented from the backward end,
2505  * it is the lightcone momentum fraction of p^- */
2506  pneg_had_1st = xfrac * pneg_string;
2507  ppos_had_1st = 0.5 * mTrn_had_1st * mTrn_had_1st / pneg_had_1st;
2508  if (ppos_had_1st > ppos_string) {
2509  return 0;
2510  }
2511  }
2512 
2513  // Add PDG id and four-momentum of the (first) hadron to the list.
2514  pdgid_frag.push_back(pdgid_had_1st);
2515  FourVector mom_had_1st = FourVector(
2516  (ppos_had_1st + pneg_had_1st) * M_SQRT1_2,
2517  evec_basis[0] * (ppos_had_1st - pneg_had_1st) * M_SQRT1_2 +
2518  evec_basis[1] * QTrx_had_1st + evec_basis[2] * QTry_had_1st);
2519  momentum_frag.push_back(mom_had_1st);
2520 
2521  // Update lightcone momentum of the string.
2522  ppos_string -= ppos_had_1st;
2523  pneg_string -= pneg_had_1st;
2524  /* Update flavor and transverse momentum of the string end,
2525  * from which the (first) hadron is fragmented.
2526  * Flavor of the new string end is antiparticle of
2527  * the constituent taken by the hadron.
2528  * Transverse momentum of the new string end is opposite to that
2529  * of the constituent taken by the hadron. */
2530  if (from_forward) {
2531  /* Update the forward end of the string
2532  * if hadron is fragmented from there. */
2533  flav_string_pos.anti(flav_new);
2534  QTrx_string_pos = -QTrx_new;
2535  QTry_string_pos = -QTry_new;
2536  } else {
2537  /* Update the backward end of the string
2538  * if hadron is fragmented from there. */
2539  flav_string_neg.anti(flav_new);
2540  QTrx_string_neg = -QTrx_new;
2541  QTry_string_neg = -QTry_new;
2542  }
2543 
2544  n_frag += 1;
2545  }
2546 
2547  return n_frag;
2548 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_hadrontype_from_quark()

int smash::StringProcess::get_hadrontype_from_quark ( int  idq1,
int  idq2 
)

Determines hadron type from valence quark constituents.

First, try with PYTHIA routine. If it does not work, select a resonance with the same quantum numbers. The probability to pick each resonance in this case is proportional to spin degeneracy / mass, which is inspired by UrQMD.

Parameters
[in]idq1PDG id of a valence quark constituent.
[in]idq2PDG id of another valence quark constituent.
Returns
PDG id of selected hadronic species.

Definition at line 2550 of file processstring.cc.

2550  {
2551  const int baryon_number =
2552  pythia_hadron_->particleData.baryonNumberType(idq1) +
2553  pythia_hadron_->particleData.baryonNumberType(idq2);
2554 
2555  int pdgid_hadron = 0;
2556  /* PDG id of the leading baryon from valence quark constituent.
2557  * First, try with the PYTHIA machinary. */
2558  Pythia8::FlavContainer flav1 = Pythia8::FlavContainer(idq1);
2559  Pythia8::FlavContainer flav2 = Pythia8::FlavContainer(idq2);
2560  const int n_try = 10;
2561  for (int i_try = 0; i_try < n_try; i_try++) {
2562  pdgid_hadron = pythia_stringflav_.combine(flav1, flav2);
2563  if (pdgid_hadron != 0) {
2564  return pdgid_hadron;
2565  }
2566  }
2567 
2568  /* If PYTHIA machinary does not work, determine type of the leading baryon
2569  * based on the quantum numbers and mass. */
2570 
2571  // net quark number of d, u, s, c and b flavors
2572  std::array<int, 5> frag_net_q;
2573  /* Evaluate total net quark number of baryon (antibaryon)
2574  * from the valence quark constituents. */
2575  for (int iq = 0; iq < 5; iq++) {
2576  int nq1 =
2577  pythia_hadron_->particleData.nQuarksInCode(std::abs(idq1), iq + 1);
2578  int nq2 =
2579  pythia_hadron_->particleData.nQuarksInCode(std::abs(idq2), iq + 1);
2580  nq1 = idq1 > 0 ? nq1 : -nq1;
2581  nq2 = idq2 > 0 ? nq2 : -nq2;
2582  frag_net_q[iq] = nq1 + nq2;
2583  }
2584  const int frag_iso3 = frag_net_q[1] - frag_net_q[0];
2585  const int frag_strange = -frag_net_q[2];
2586  const int frag_charm = frag_net_q[3];
2587  const int frag_bottom = -frag_net_q[4];
2588  logg[LPythia].debug(" conserved charges : iso3 = ", frag_iso3,
2589  ", strangeness = ", frag_strange,
2590  ", charmness = ", frag_charm,
2591  ", bottomness = ", frag_bottom);
2592 
2593  std::vector<int> pdgid_possible;
2594  std::vector<double> weight_possible;
2595  std::vector<double> weight_summed;
2596  /* loop over hadronic species
2597  * Any hadron with the same valence quark contents is allowed and
2598  * the probability goes like spin degeneracy over mass. */
2599  for (auto &ptype : ParticleType::list_all()) {
2600  if (!ptype.is_hadron()) {
2601  continue;
2602  }
2603  const int pdgid = ptype.pdgcode().get_decimal();
2604  if ((pythia_hadron_->particleData.isParticle(pdgid)) &&
2605  (baryon_number == 3 * ptype.pdgcode().baryon_number()) &&
2606  (frag_iso3 == ptype.pdgcode().isospin3()) &&
2607  (frag_strange == ptype.pdgcode().strangeness()) &&
2608  (frag_charm == ptype.pdgcode().charmness()) &&
2609  (frag_bottom == ptype.pdgcode().bottomness())) {
2610  const int spin_degeneracy = ptype.pdgcode().spin_degeneracy();
2611  const double mass_pole = ptype.mass();
2612  const double weight = static_cast<double>(spin_degeneracy) / mass_pole;
2613  pdgid_possible.push_back(pdgid);
2614  weight_possible.push_back(weight);
2615 
2616  logg[LPythia].debug(" PDG id ", pdgid, " is possible with weight ",
2617  weight);
2618  }
2619  }
2620  const int n_possible = pdgid_possible.size();
2621  weight_summed.push_back(0.);
2622  for (int i = 0; i < n_possible; i++) {
2623  weight_summed.push_back(weight_summed[i] + weight_possible[i]);
2624  }
2625 
2626  /* Sample baryon (antibaryon) specie,
2627  * which is fragmented from the leading diquark (anti-diquark). */
2628  const double uspc = random::uniform(0., weight_summed[n_possible]);
2629  for (int i = 0; i < n_possible; i++) {
2630  if ((uspc >= weight_summed[i]) && (uspc < weight_summed[i + 1])) {
2631  return pdgid_possible[i];
2632  }
2633  }
2634 
2635  return 0;
2636 }
Here is the call graph for this function:

◆ get_resonance_from_quark()

int smash::StringProcess::get_resonance_from_quark ( int  idq1,
int  idq2,
double  mass 
)
Parameters
[in]idq1id of the valence quark (anti-diquark)
[in]idq2id of the valence anti-quark (diquark)
[in]massmass of the resonance.
Returns
PDG id of resonance with the closest mass. If the mass is below the threshold or the input PDG id is invalid, 0 is returned.

Definition at line 2638 of file processstring.cc.

2638  {
2639  // if the mass is too low, return 0 (failure).
2640  if (mass < pion_mass) {
2641  return 0;
2642  }
2643 
2644  /* It checks whether one has a valid input
2645  * the string ends. */
2646 
2647  // idq1 is supposed to be a quark or anti-diquark.
2648  bool end1_is_quark = idq1 > 0 && pythia_hadron_->particleData.isQuark(idq1);
2649  bool end1_is_antidiq =
2650  idq1 < 0 && pythia_hadron_->particleData.isDiquark(idq1);
2651  // idq2 is supposed to be a anti-quark or diquark.
2652  bool end2_is_antiq = idq2 < 0 && pythia_hadron_->particleData.isQuark(idq2);
2653  bool end2_is_diquark =
2654  idq2 > 0 && pythia_hadron_->particleData.isDiquark(idq2);
2655 
2656  int baryon;
2657  if (end1_is_quark) {
2658  if (end2_is_antiq) {
2659  // we have a mesonic resonance from a quark-antiquark pair.
2660  baryon = 0;
2661  } else if (end2_is_diquark) {
2662  // we have a baryonic resonance from a quark-diquark pair.
2663  baryon = 1;
2664  } else {
2665  return 0;
2666  }
2667  } else if (end1_is_antidiq) {
2668  if (end2_is_antiq) {
2669  // we have a antibaryonic resonance from a antiquark-antidiquark pair.
2670  baryon = -1;
2671  } else {
2672  return 0;
2673  }
2674  } else {
2675  return 0;
2676  }
2677 
2678  /* array for the net quark numbers of the constituents.
2679  * net_qnumber[0, 1, 2, 3 and 4] correspond respectively to
2680  * d, u, s, c, b quark flavors. */
2681  std::array<int, 5> net_qnumber;
2682  for (int iflav = 0; iflav < 5; iflav++) {
2683  net_qnumber[iflav] = 0;
2684 
2685  int qnumber1 =
2686  pythia_hadron_->particleData.nQuarksInCode(std::abs(idq1), iflav + 1);
2687  if (idq1 < 0) {
2688  // anti-diquark gets an extra minus sign.
2689  qnumber1 = -qnumber1;
2690  }
2691  net_qnumber[iflav] += qnumber1;
2692 
2693  int qnumber2 =
2694  pythia_hadron_->particleData.nQuarksInCode(std::abs(idq2), iflav + 1);
2695  if (idq2 < 0) {
2696  // anti-quark gets an extra minus sign.
2697  qnumber2 = -qnumber2;
2698  }
2699  net_qnumber[iflav] += qnumber2;
2700  }
2701 
2702  // List of PDG ids of resonances with the same quantum number.
2703  std::vector<int> pdgid_possible;
2704  // Corresponding mass differences.
2705  std::vector<double> mass_diff;
2706  for (auto &ptype : ParticleType::list_all()) {
2707  if (!ptype.is_hadron() || ptype.is_stable() ||
2708  ptype.pdgcode().baryon_number() != baryon) {
2709  // Only resonances with the same baryon number are considered.
2710  continue;
2711  }
2712  const int pdgid = ptype.pdgcode().get_decimal();
2713  const double mass_min = ptype.min_mass_spectral();
2714  if (mass < mass_min) {
2715  // A resoance with mass lower than its minimum threshold is not allowed.
2716  continue;
2717  }
2718 
2719  if (ptype.pdgcode().isospin3() != net_qnumber[1] - net_qnumber[0]) {
2720  // check isospin3.
2721  continue;
2722  }
2723  if (ptype.pdgcode().strangeness() != -net_qnumber[2]) {
2724  // check strangeness.
2725  continue;
2726  }
2727  if (ptype.pdgcode().charmness() != net_qnumber[3]) {
2728  // check charmness.
2729  continue;
2730  }
2731  if (ptype.pdgcode().bottomness() != -net_qnumber[4]) {
2732  // check bottomness.
2733  continue;
2734  }
2735 
2736  const double mass_pole = ptype.mass();
2737  // Add the PDG id and mass difference to the vector array.
2738  pdgid_possible.push_back(pdgid);
2739  mass_diff.push_back(mass - mass_pole);
2740  }
2741 
2742  const int n_res = pdgid_possible.size();
2743  if (n_res == 0) {
2744  // If there is no possible resonance found, return 0 (failure).
2745  return 0;
2746  }
2747 
2748  int ires_closest = 0;
2749  double mass_diff_min = std::fabs(mass_diff[0]);
2750  /* Find a resonance whose pole mass is closest to
2751  * the input mass. */
2752  for (int ires = 1; ires < n_res; ires++) {
2753  if (std::fabs(mass_diff[ires]) < mass_diff_min) {
2754  ires_closest = ires;
2755  mass_diff_min = mass_diff[ires];
2756  }
2757  }
2758  logg[LPythia].debug("Quark constituents ", idq1, " and ", idq2, " with mass ",
2759  mass, " (GeV) turned into a resonance ",
2760  pdgid_possible[ires_closest]);
2761  return pdgid_possible[ires_closest];
2762 }
Here is the call graph for this function:

◆ make_lightcone_final_two()

bool smash::StringProcess::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 StringFragmentation::finalTwo in StringFragmentation.cc of PYTHIA 8.

Parameters
[in]separate_fragment_hadronwhether a separate fragmentation function is used for the forward hadron
[in]ppos_stringlightcone momentum p^+ of the string
[in]pneg_stringligntcone momentum p^- of the string
[in]mTrn_had_forwardtransverse mass of the forward hadron
[in]mTrn_had_backwardtransverse mass of the backward hadron
[out]ppos_had_forwardlightcone momentum p^+ of the forward hadron
[out]ppos_had_backwardlightcone momentum p^+ of the backward hadron
[out]pneg_had_forwardlightcone momentum p^- of the forward hadron
[out]pneg_had_backwardlightcone momentum p^- of the backward hadron
Returns
if the lightcone momenta are properly determined such that energy and momentum are conserved.

Definition at line 2764 of file processstring.cc.

2768  {
2769  const double mTsqr_string = 2. * ppos_string * pneg_string;
2770  if (mTsqr_string < 0.) {
2771  return false;
2772  }
2773  const double mTrn_string = std::sqrt(mTsqr_string);
2774  if (mTrn_string < mTrn_had_forward + mTrn_had_backward) {
2775  return false;
2776  }
2777 
2778  // square of transvere mass of the forward hadron
2779  const double mTsqr_had_forward = mTrn_had_forward * mTrn_had_forward;
2780  // square of transvere mass of the backward hadron
2781  const double mTsqr_had_backward = mTrn_had_backward * mTrn_had_backward;
2782 
2783  /* The following part determines lightcone momentum fraction of p^+
2784  * carried by each hadron.
2785  * Lightcone momenta of the forward and backward hadrons are
2786  * p^+ forward = (xe_pos + xpz_pos) * p^+ string,
2787  * p^- forward = (xe_pos - xpz_pos) * p^- string,
2788  * p^+ backward = (xe_neg - xpz_pos) * p^+ string and
2789  * p^- backward = (xe_neg + xpz_pos) * p^- string.
2790  * where xe_pos and xe_neg satisfy xe_pos + xe_neg = 1.
2791  * Then evaluate xe_pos, xe_neg and xpz_pos in terms of
2792  * the transverse masses of hadrons and string. */
2793 
2794  // Express xe_pos and xe_neg in terms of the transverse masses.
2795  const double xm_diff =
2796  (mTsqr_had_forward - mTsqr_had_backward) / mTsqr_string;
2797  const double xe_pos = 0.5 * (1. + xm_diff);
2798  const double xe_neg = 0.5 * (1. - xm_diff);
2799 
2800  // Express xpz_pos in terms of the transverse masses.
2801  const double lambda_sqr =
2802  pow_int(mTsqr_string - mTsqr_had_forward - mTsqr_had_backward, 2) -
2803  4. * mTsqr_had_forward * mTsqr_had_backward;
2804  if (lambda_sqr <= 0.) {
2805  return false;
2806  }
2807  const double lambda = std::sqrt(lambda_sqr);
2808  const double b_lund =
2809  separate_fragment_hadron ? stringz_b_leading_ : stringz_b_produce_;
2810  /* The probability to flip sign of xpz_pos is taken from
2811  * StringFragmentation::finalTwo in StringFragmentation.cc
2812  * of PYTHIA 8. */
2813  const double prob_reverse =
2814  std::exp(-b_lund * lambda) / (1. + std::exp(-b_lund * lambda));
2815  double xpz_pos = 0.5 * lambda / mTsqr_string;
2816  if (random::uniform(0., 1.) < prob_reverse) {
2817  xpz_pos = -xpz_pos;
2818  }
2819 
2820  ppos_had_forward = (xe_pos + xpz_pos) * ppos_string;
2821  ppos_had_backward = (xe_neg - xpz_pos) * ppos_string;
2822 
2823  pneg_had_forward = 0.5 * mTsqr_had_forward / ppos_had_forward;
2824  pneg_had_backward = 0.5 * mTsqr_had_backward / ppos_had_backward;
2825 
2826  return true;
2827 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ sample_zLund()

double smash::StringProcess::sample_zLund ( double  a,
double  b,
double  mTrn 
)
static

Sample lightcone momentum fraction according to the LUND fragmentation function.

\( f(z) = \frac{1}{z} (1 - z)^a \exp{ \left(- \frac{b m_T^2}{z} \right) } \)

Parameters
[in]aparameter for the fragmentation function
[in]bparameter for the fragmentation function
[in]mTrntransverse mass of the fragmented hadron
Returns
sampled lightcone momentum fraction

Definition at line 2829 of file processstring.cc.

2829  {
2830  // the lightcone momentum fraction x
2831  double xfrac = 0.;
2832  bool xfrac_accepted = false;
2833  /* First sample the inverse 1/x of the lightcone momentum fraction.
2834  * Then, obtain x itself.
2835  * The probability distribution function for the inverse of x is
2836  * PDF(u = 1/x) = (1/u) * (1 - 1/u)^a * exp(-b * mTrn^2 * u)
2837  * with 1 < u < infinity.
2838  * The rejection method can be used with an envelop function
2839  * ENV(u) = exp(-b * mTrn^2 * u). */
2840  while (!xfrac_accepted) {
2841  const double fac_env = b * mTrn * mTrn;
2842  const double u_aux = random::uniform(0., 1.);
2843  /* Sample u = 1/x according to the envelop function
2844  * ENV(u) = exp(-b * mTrn^2 * u). */
2845  const double xfrac_inv = 1. - std::log(u_aux) / fac_env;
2846  assert(xfrac_inv >= 1.);
2847  /* Evaluate the ratio of the real probability distribution function to
2848  * the envelop function. */
2849  const double xf_ratio = std::pow(1. - 1. / xfrac_inv, a) / xfrac_inv;
2850  // Determine whether the sampled value will be accepted.
2851  if (random::uniform(0., 1.) <= xf_ratio) {
2852  /* If the sampled value of 1/x is accepted,
2853  * obtain the value of x. */
2854  xfrac = 1. / xfrac_inv;
2855  xfrac_accepted = true;
2856  }
2857  }
2858  return xfrac;
2859 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ remake_kinematics_fragments()

bool smash::StringProcess::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 
)
Parameters
[out]event_fragmentsevent record which contains information of particles
[in]evec_basisthree orthonormal basis vectors of which evec_basis[0] is in the longitudinal direction while evec_basis[1] and evec_basis[2] span the transverse plane.
[in]ppos_stringlightcone momentum p^+ of the string
[in]pneg_stringligntcone momentum p^- of the string
[in]QTrx_stringtransverse momentum px of the string
[in]QTry_stringtransverse momentum py of the string
[in]QTrx_add_postransverse momentum px to be added to the most forward hadron
[in]QTry_add_postransverse momentum py to be added to the most forward hadron
[in]QTrx_add_negtransverse momentum px to be added to the most backward hadron
[in]QTry_add_negtransverse momentum py to be added to the most backward hadron

Definition at line 2861 of file processstring.cc.

2865  {
2866  logg[LPythia].debug("Correcting the kinematics of fragmented hadrons...");
2867 
2868  if (ppos_string < 0. || pneg_string < 0.) {
2869  logg[LPythia].debug(
2870  " wrong lightcone momenta of string : ppos_string (GeV) = ",
2871  ppos_string, " pneg_string (GeV) = ", pneg_string);
2872  return false;
2873  }
2874  // Momentum rapidity of the final string
2875  const double yrapid_string = 0.5 * std::log(ppos_string / pneg_string);
2876  logg[LOutput].debug("Momentum-space rapidity of the string should be ",
2877  yrapid_string);
2878 
2879  // Transverse mass of the final string
2880  const double mTrn_string = std::sqrt(2. * ppos_string * pneg_string);
2881  logg[LOutput].debug("Transvere mass (GeV) of the string should be ",
2882  mTrn_string);
2883  // Transverse momentum of the final string
2884  const double QTrn_string =
2885  std::sqrt(QTrx_string * QTrx_string + QTry_string * QTry_string);
2886  if (mTrn_string < QTrn_string) {
2887  logg[LOutput].debug(
2888  " wrong transverse mass of string : mTrn_string (GeV) = ", mTrn_string,
2889  " QTrn_string (GeV) = ", QTrn_string);
2890  return false;
2891  }
2892  const double msqr_string =
2893  mTrn_string * mTrn_string - QTrn_string * QTrn_string;
2894  // Mass of the final string
2895  const double mass_string = std::sqrt(msqr_string);
2896  logg[LOutput].debug("The string mass (GeV) should be ", mass_string);
2897 
2898  /* If there is no transverse momentum to be added to the string ends,
2899  * skip the entire procedure and return. */
2900  if (std::fabs(QTrx_add_pos) < small_number * mass_string &&
2901  std::fabs(QTry_add_pos) < small_number * mass_string &&
2902  std::fabs(QTrx_add_neg) < small_number * mass_string &&
2903  std::fabs(QTry_add_neg) < small_number * mass_string) {
2904  logg[LOutput].debug(" no need to add transverse momenta - skipping.");
2905  return true;
2906  }
2907 
2908  FourVector ptot_string_ini = FourVector(0., 0., 0., 0.);
2909  // Compute total four-momentum of the initial string.
2910  for (int ipyth = 1; ipyth < event_fragments.size(); ipyth++) {
2911  if (!event_fragments[ipyth].isFinal()) {
2912  continue;
2913  }
2914 
2915  FourVector p_frag =
2916  FourVector(event_fragments[ipyth].e(), event_fragments[ipyth].px(),
2917  event_fragments[ipyth].py(), event_fragments[ipyth].pz());
2918  ptot_string_ini += p_frag;
2919  }
2920  const double E_string_ini = ptot_string_ini.x0();
2921  const double pz_string_ini = ptot_string_ini.threevec() * evec_basis[0];
2922  const double ppos_string_ini = (E_string_ini + pz_string_ini) * M_SQRT1_2;
2923  const double pneg_string_ini = (E_string_ini - pz_string_ini) * M_SQRT1_2;
2924  // Compute the momentum rapidity of the initial string.
2925  const double yrapid_string_ini =
2926  0.5 * std::log(ppos_string_ini / pneg_string_ini);
2927  /* Then, boost into the frame in which string is at rest in the
2928  * longitudinal direction. */
2929  shift_rapidity_event(event_fragments, evec_basis, 1., -yrapid_string_ini);
2930 
2931  int ip_forward = 0;
2932  int ip_backward = 0;
2933  double y_forward = 0.;
2934  double y_backward = 0.;
2935  ptot_string_ini = FourVector(0., 0., 0., 0.);
2936  // Find the most forward and backward hadrons based on the momentum rapidity.
2937  for (int ipyth = 1; ipyth < event_fragments.size(); ipyth++) {
2938  if (!event_fragments[ipyth].isFinal()) {
2939  continue;
2940  }
2941 
2942  FourVector p_frag =
2943  FourVector(event_fragments[ipyth].e(), event_fragments[ipyth].px(),
2944  event_fragments[ipyth].py(), event_fragments[ipyth].pz());
2945  ptot_string_ini += p_frag;
2946 
2947  const double E_frag = p_frag.x0();
2948  const double pl_frag = p_frag.threevec() * evec_basis[0];
2949  double y_current = 0.5 * std::log((E_frag + pl_frag) / (E_frag - pl_frag));
2950  if (y_current > y_forward) {
2951  ip_forward = ipyth;
2952  y_forward = y_current;
2953  }
2954  if (y_current < y_backward) {
2955  ip_backward = ipyth;
2956  y_backward = y_current;
2957  }
2958  }
2959  logg[LOutput].debug(" The most forward hadron is ip_forward = ", ip_forward,
2960  " with rapidity ", y_forward);
2961  logg[LOutput].debug(" The most backward hadron is ip_backward = ",
2962  ip_backward, " with rapidity ", y_backward);
2963 
2964  const double px_string_ini = ptot_string_ini.threevec() * evec_basis[1];
2965  const double py_string_ini = ptot_string_ini.threevec() * evec_basis[2];
2966 
2967  /* Check if the transverse momentum px is conserved i.e.,
2968  * px of the initial string + px to be added = px of the final string */
2969  bool correct_px = std::fabs(px_string_ini + QTrx_add_pos + QTrx_add_neg -
2970  QTrx_string) < small_number * mass_string;
2971  if (!correct_px) {
2972  logg[LOutput].debug(
2973  " input transverse momenta in x-axis are not consistent.");
2974  return false;
2975  }
2976  /* Check if the transverse momentum py is conserved i.e.,
2977  * py of the initial string + py to be added = py of the final string */
2978  bool correct_py = std::fabs(py_string_ini + QTry_add_pos + QTry_add_neg -
2979  QTry_string) < small_number * mass_string;
2980  if (!correct_py) {
2981  logg[LOutput].debug(
2982  " input transverse momenta in y-axis are not consistent.");
2983  return false;
2984  }
2985 
2986  Pythia8::Vec4 pvec_string_now =
2987  set_Vec4(ptot_string_ini.x0(), ptot_string_ini.threevec());
2988 
2989  logg[LOutput].debug(
2990  " Adding transverse momentum to the most forward hadron.");
2991  pvec_string_now -= event_fragments[ip_forward].p();
2992  const double mass_frag_pos = event_fragments[ip_forward].p().mCalc();
2993  // Four-momentum of the most forward hadron
2994  FourVector p_old_frag_pos = FourVector(
2995  event_fragments[ip_forward].e(), event_fragments[ip_forward].px(),
2996  event_fragments[ip_forward].py(), event_fragments[ip_forward].pz());
2997  // Add transverse momentum to it.
2998  ThreeVector mom_new_frag_pos = p_old_frag_pos.threevec() +
2999  QTrx_add_pos * evec_basis[1] +
3000  QTry_add_pos * evec_basis[2];
3001  // Re-calculate the energy.
3002  double E_new_frag_pos =
3003  std::sqrt(mom_new_frag_pos.sqr() + mass_frag_pos * mass_frag_pos);
3004  Pythia8::Vec4 pvec_new_frag_pos = set_Vec4(E_new_frag_pos, mom_new_frag_pos);
3005  pvec_string_now += pvec_new_frag_pos;
3006  // Update the event record.
3007  event_fragments[ip_forward].p(pvec_new_frag_pos);
3008 
3009  logg[LOutput].debug(
3010  " Adding transverse momentum to the most backward hadron.");
3011  pvec_string_now -= event_fragments[ip_backward].p();
3012  const double mass_frag_neg = event_fragments[ip_backward].p().mCalc();
3013  // Four-momentum of the most backward hadron
3014  FourVector p_old_frag_neg = FourVector(
3015  event_fragments[ip_backward].e(), event_fragments[ip_backward].px(),
3016  event_fragments[ip_backward].py(), event_fragments[ip_backward].pz());
3017  // Add transverse momentum to it.
3018  ThreeVector mom_new_frag_neg = p_old_frag_neg.threevec() +
3019  QTrx_add_neg * evec_basis[1] +
3020  QTry_add_neg * evec_basis[2];
3021  // Re-calculate the energy.
3022  double E_new_frag_neg =
3023  std::sqrt(mom_new_frag_neg.sqr() + mass_frag_neg * mass_frag_neg);
3024  Pythia8::Vec4 pvec_new_frag_neg = set_Vec4(E_new_frag_neg, mom_new_frag_neg);
3025  pvec_string_now += pvec_new_frag_neg;
3026  // Update the event record.
3027  event_fragments[ip_backward].p(pvec_new_frag_neg);
3028 
3029  // Update the event record with total four-momentum of the current string.
3030  event_fragments[0].p(pvec_string_now);
3031  event_fragments[0].m(pvec_string_now.mCalc());
3032 
3033  int n_frag = 0;
3034  // Sum of transverse masses of all fragmented hadrons.
3035  double mTrn_frag_all = 0.;
3036  for (int ipyth = 1; ipyth < event_fragments.size(); ipyth++) {
3037  if (!event_fragments[ipyth].isFinal()) {
3038  continue;
3039  }
3040 
3041  n_frag += 1;
3042  FourVector p_frag =
3043  FourVector(event_fragments[ipyth].e(), event_fragments[ipyth].px(),
3044  event_fragments[ipyth].py(), event_fragments[ipyth].pz());
3045  ptot_string_ini += p_frag;
3046 
3047  const double E_frag = p_frag.x0();
3048  const double pl_frag = p_frag.threevec() * evec_basis[0];
3049  const double ppos_frag = (E_frag + pl_frag) * M_SQRT1_2;
3050  const double pneg_frag = (E_frag - pl_frag) * M_SQRT1_2;
3051  const double mTrn_frag = std::sqrt(2. * ppos_frag * pneg_frag);
3052  mTrn_frag_all += mTrn_frag;
3053  }
3054  logg[LOutput].debug(
3055  "Sum of transverse masses (GeV) of all fragmented hadrons : ",
3056  mTrn_frag_all);
3057  /* If the transverse mass of the (final) string is smaller than
3058  * the sum of transverse masses, kinematics cannot be determined. */
3059  if (mTrn_string < mTrn_frag_all) {
3060  logg[LOutput].debug(" which is larger than mT of the actual string ",
3061  mTrn_string);
3062  return false;
3063  }
3064 
3065  double mass_string_now = pvec_string_now.mCalc();
3066  double msqr_string_now = mass_string_now * mass_string_now;
3067  // Total four-momentum of the current string
3068  FourVector p_string_now =
3069  FourVector(pvec_string_now.e(), pvec_string_now.px(),
3070  pvec_string_now.py(), pvec_string_now.pz());
3071  double E_string_now = p_string_now.x0();
3072  double pz_string_now = p_string_now.threevec() * evec_basis[0];
3073  logg[LOutput].debug("The string mass (GeV) at this point : ",
3074  mass_string_now);
3075  double ppos_string_now = (E_string_now + pz_string_now) * M_SQRT1_2;
3076  double pneg_string_now = (E_string_now - pz_string_now) * M_SQRT1_2;
3077  // Momentum rapidity of the current string
3078  double yrapid_string_now = 0.5 * std::log(ppos_string_now / pneg_string_now);
3079  logg[LOutput].debug("The momentum-space rapidity of string at this point : ",
3080  yrapid_string_now);
3081  logg[LOutput].debug(
3082  "The momentum-space rapidities of hadrons will be changed.");
3083  const int niter_max = 10000;
3084  bool accepted = false;
3085  double fac_all_yrapid = 1.;
3086  /* Rescale momentum rapidities of hadrons by replacing
3087  * y_hadron with y_string_now + fac_yrapid * (y_hadron - y_string_now).
3088  * This is done iteratively by finding the value of fac_yrapid which gives
3089  * the correct string mass. */
3090  for (int iiter = 0; iiter < niter_max; iiter++) {
3091  if (std::fabs(mass_string_now - mass_string) < really_small * mass_string) {
3092  accepted = true;
3093  break;
3094  }
3095  double E_deriv = 0.;
3096  double pz_deriv = 0.;
3097 
3098  /* Have a Taylor series of mass square as a linear function
3099  * of fac_yrapid and find a trial value of fac_yrapid. */
3100  for (int ipyth = 1; ipyth < event_fragments.size(); ipyth++) {
3101  if (!event_fragments[ipyth].isFinal()) {
3102  continue;
3103  }
3104 
3105  FourVector p_frag =
3106  FourVector(event_fragments[ipyth].e(), event_fragments[ipyth].px(),
3107  event_fragments[ipyth].py(), event_fragments[ipyth].pz());
3108  const double E_frag = p_frag.x0();
3109  const double pl_frag = p_frag.threevec() * evec_basis[0];
3110  const double ppos_frag = (E_frag + pl_frag) * M_SQRT1_2;
3111  const double pneg_frag = (E_frag - pl_frag) * M_SQRT1_2;
3112  const double mTrn_frag = std::sqrt(2. * ppos_frag * pneg_frag);
3113  const double y_frag = 0.5 * std::log(ppos_frag / pneg_frag);
3114 
3115  E_deriv += mTrn_frag * (y_frag - yrapid_string_now) * std::sinh(y_frag);
3116  pz_deriv += mTrn_frag * (y_frag - yrapid_string_now) * std::cosh(y_frag);
3117  }
3118  double slope = 2. * (E_string_now * E_deriv - pz_string_now * pz_deriv);
3119  double fac_yrapid = 1. + std::tanh((msqr_string - msqr_string_now) / slope);
3120  fac_all_yrapid *= fac_yrapid;
3121 
3122  // Replace momentum rapidities of hadrons.
3123  shift_rapidity_event(event_fragments, evec_basis, fac_yrapid,
3124  (1. - fac_yrapid) * yrapid_string_now);
3125  // Update the four-momentum and mass of the current string
3126  pvec_string_now = event_fragments[0].p();
3127  mass_string_now = pvec_string_now.mCalc();
3128  msqr_string_now = mass_string_now * mass_string_now;
3129  p_string_now = FourVector(pvec_string_now.e(), pvec_string_now.px(),
3130  pvec_string_now.py(), pvec_string_now.pz());
3131  E_string_now = p_string_now.x0();
3132  pz_string_now = p_string_now.threevec() * evec_basis[0];
3133  ppos_string_now = (E_string_now + pz_string_now) * M_SQRT1_2;
3134  pneg_string_now = (E_string_now - pz_string_now) * M_SQRT1_2;
3135  yrapid_string_now = 0.5 * std::log(ppos_string_now / pneg_string_now);
3136  logg[LOutput].debug(" step ", iiter + 1, " : fac_yrapid = ", fac_yrapid,
3137  " , string mass (GeV) = ", mass_string_now,
3138  " , string rapidity = ", yrapid_string_now);
3139  }
3140 
3141  if (!accepted) {
3142  logg[LOutput].debug(" Too many iterations in rapidity rescaling.");
3143  return false;
3144  }
3145  logg[LOutput].debug(
3146  "The overall factor multiplied to the rapidities of hadrons = ",
3147  fac_all_yrapid);
3148  logg[LOutput].debug("The momentum-space rapidity of string at this point : ",
3149  yrapid_string_now);
3150  const double y_diff = yrapid_string - yrapid_string_now;
3151  logg[LOutput].debug("The hadrons will be boosted by rapidity ", y_diff,
3152  " for the longitudinal momentum conservation.");
3153 
3154  // Boost the hadrons back into the original frame.
3155  shift_rapidity_event(event_fragments, evec_basis, 1., y_diff);
3156 
3157  return true;
3158 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ shift_rapidity_event()

void smash::StringProcess::shift_rapidity_event ( Pythia8::Event &  event,
std::array< ThreeVector, 3 > &  evec_basis,
double  factor_yrapid,
double  diff_yrapid 
)
inline

Shift the momentum rapidity of all particles in a given event record.

y to factor_yrapid * y + diff_yrapid

Parameters
[out]eventevent record which contains information of particles
[in]evec_basisthree orthonormal basis vectors of which evec_basis[0] is in the longitudinal direction while evec_basis[1] and evec_basis[2] span the transverse plane.
[in]factor_yrapidfactor multiplied to the old rapidity
[in]diff_yrapidrapidity difference added to the old one

Definition at line 1028 of file processstring.h.

1030  {
1031  Pythia8::Vec4 pvec_string_now = Pythia8::Vec4(0., 0., 0., 0.);
1032  // loop over all particles in the record
1033  for (int ipyth = 1; ipyth < event.size(); ipyth++) {
1034  if (!event[ipyth].isFinal()) {
1035  continue;
1036  }
1037 
1038  FourVector p_frag = FourVector(
1039  event[ipyth].e(), event[ipyth].px(),
1040  event[ipyth].py(), event[ipyth].pz());
1041  const double E_frag = p_frag.x0();
1042  const double pl_frag = p_frag.threevec() * evec_basis[0];
1043  const double ppos_frag = (E_frag + pl_frag) * M_SQRT1_2;
1044  const double pneg_frag = (E_frag - pl_frag) * M_SQRT1_2;
1045  const double mTrn_frag = std::sqrt(2. * ppos_frag * pneg_frag);
1046  // evaluate the old momentum rapidity
1047  const double y_frag = 0.5 * std::log(ppos_frag / pneg_frag);
1048 
1049  // obtain the new momentum rapidity
1050  const double y_new_frag = factor_yrapid * y_frag + diff_yrapid;
1051  // compute the new four momentum
1052  const double E_new_frag = mTrn_frag * std::cosh(y_new_frag);
1053  const double pl_new_frag = mTrn_frag * std::sinh(y_new_frag);
1054  ThreeVector mom_new_frag =
1055  p_frag.threevec() + (pl_new_frag - pl_frag) * evec_basis[0];
1056  Pythia8::Vec4 pvec_new_frag = set_Vec4(E_new_frag, mom_new_frag);
1057  event[ipyth].p(pvec_new_frag);
1058  pvec_string_now += pvec_new_frag;
1059  }
1060  event[0].p(pvec_string_now);
1061  event[0].m(pvec_string_now.mCalc());
1062  }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ assign_all_scaling_factors()

void smash::StringProcess::assign_all_scaling_factors ( int  baryon_string,
ParticleList &  outgoing_particles,
const ThreeVector evecLong,
double  suppression_factor 
)
static

Assign a cross section scaling factor to all outgoing particles.

The factor is only non-zero, when the outgoing particle carries a valence quark from the excited hadron. The assigned cross section scaling factor is equal to the number of the valence quarks from the fragmented hadron contained in the fragment divided by the total number of valence quarks of that fragment multiplied by a coherence factor

Parameters
[in]baryon_stringbaryon number of the string
[out]outgoing_particleslist of string fragments to which scaling factors are assigned
[in]evecLongdirection in which the string is stretched
[in]suppression_factoradditional coherence factor to be multiplied with scaling factor

Definition at line 3192 of file processstring.cc.

3195  {
3196  // Set each particle's cross section scaling factor to 0 first
3197  for (ParticleData &data : outgoing_particles) {
3198  data.set_cross_section_scaling_factor(0.0);
3199  }
3200  // sort outgoing particles according to the longitudinal velocity
3201  std::sort(outgoing_particles.begin(), outgoing_particles.end(),
3202  [&](ParticleData i, ParticleData j) {
3203  return i.momentum().velocity() * evecLong >
3204  j.momentum().velocity() * evecLong;
3205  });
3206  int nq1, nq2; // number of quarks at both ends of the string
3207  switch (baryon_string) {
3208  case 0:
3209  nq1 = -1;
3210  nq2 = 1;
3211  break;
3212  case 1:
3213  nq1 = 2;
3214  nq2 = 1;
3215  break;
3216  case -1:
3217  nq1 = -2;
3218  nq2 = -1;
3219  break;
3220  default:
3221  throw std::runtime_error("string is neither mesonic nor baryonic");
3222  }
3223  // Try to find nq1 on one string end and nq2 on the other string end and the
3224  // other way around. When the leading particles are close to the string ends,
3225  // the quarks are assumed to be distributed this way.
3226  std::pair<int, int> i = find_leading(nq1, nq2, outgoing_particles);
3227  std::pair<int, int> j = find_leading(nq2, nq1, outgoing_particles);
3228  if (baryon_string == 0 && i.second - i.first < j.second - j.first) {
3229  assign_scaling_factor(nq2, outgoing_particles[j.first], suppression_factor);
3230  assign_scaling_factor(nq1, outgoing_particles[j.second],
3231  suppression_factor);
3232  } else {
3233  assign_scaling_factor(nq1, outgoing_particles[i.first], suppression_factor);
3234  assign_scaling_factor(nq2, outgoing_particles[i.second],
3235  suppression_factor);
3236  }
3237 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ find_leading()

std::pair< int, int > smash::StringProcess::find_leading ( int  nq1,
int  nq2,
ParticleList &  list 
)
static

Find the leading string fragments.

Find the first particle, which can carry nq1, and the last particle, which can carry nq2 valence quarks and return their indices in the given list.

Parameters
[in]nq1number of valence quarks from excited hadron at forward end of the string
[in]nq2number of valance quarks from excited hadron at backward end of the string
[in]listlist of string fragments
Returns
indices of the leading hadrons in list

Definition at line 3175 of file processstring.cc.

3176  {
3177  assert(list.size() >= 2);
3178  int end = list.size() - 1;
3179  int i1, i2;
3180  for (i1 = 0;
3181  i1 <= end && !list[i1].pdgcode().contains_enough_valence_quarks(nq1);
3182  i1++) {
3183  }
3184  for (i2 = end;
3185  i2 >= 0 && !list[i2].pdgcode().contains_enough_valence_quarks(nq2);
3186  i2--) {
3187  }
3188  std::pair<int, int> indices(i1, i2);
3189  return indices;
3190 }
Here is the caller graph for this function:

◆ assign_scaling_factor()

void smash::StringProcess::assign_scaling_factor ( int  nquark,
ParticleData data,
double  suppression_factor 
)
static

Assign a cross section scaling factor to the given particle.

The scaling factor is the number of quarks from the excited hadron, that the fragment carries devided by the total number of quarks in this fragment multiplied by coherence factor.

Parameters
[in]nquarknumber of valence quarks from the excited hadron contained in the given string fragment data
[out]dataparticle to assign a scaling factor to
[in]suppression_factorcoherence factor to decrease scaling factor

Definition at line 3160 of file processstring.cc.

3161  {
3162  int nbaryon = data.pdgcode().baryon_number();
3163  if (nbaryon == 0) {
3164  // Mesons always get a scaling factor of 1/2 since there is never
3165  // a q-qbar pair at the end of a string so nquark is always 1
3166  data.set_cross_section_scaling_factor(0.5 * suppression_factor);
3167  } else if (data.is_baryon()) {
3168  // Leading baryons get a factor of 2/3 if they carry 2
3169  // and 1/3 if they carry 1 of the strings valence quarks
3170  data.set_cross_section_scaling_factor(suppression_factor * nquark /
3171  (3.0 * nbaryon));
3172  }
3173 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ pdg_map_for_pythia()

int smash::StringProcess::pdg_map_for_pythia ( PdgCode pdg)
static

Take pdg code and map onto particle specie which can be handled by PYTHIA.

Positively charged baryons are mapped onto proton and other baryons are mapped onto neutrons. Same rule applies for anti-baryons. Positively (negatively) charged mesons are mapped onto pi+ (pi-). Negatively and positively charged leptons are mapped respectivly onto electron and positron. Currently, we do not have cross sections for leptons and photons with high energy, so such collisions should not happen.

Parameters
[in]pdgPdgCode that will be mapped
Returns
mapped PDG id to be used in PYTHIA
Exceptions
std::runtime_errorif the incoming particle is neither hadron nor lepton.

Definition at line 3239 of file processstring.cc.

3239  {
3240  PdgCode pdg_mapped(0x0);
3241 
3242  if (pdg.baryon_number() == 1) { // baryon
3243  pdg_mapped = pdg.charge() > 0 ? PdgCode(pdg::p) : PdgCode(pdg::n);
3244  } else if (pdg.baryon_number() == -1) { // antibaryon
3245  pdg_mapped = pdg.charge() < 0 ? PdgCode(-pdg::p) : PdgCode(-pdg::n);
3246  } else if (pdg.is_hadron()) { // meson
3247  if (pdg.charge() >= 0) {
3248  pdg_mapped = PdgCode(pdg::pi_p);
3249  } else {
3250  pdg_mapped = PdgCode(pdg::pi_m);
3251  }
3252  } else if (pdg.is_lepton()) { // lepton
3253  pdg_mapped = pdg.charge() < 0 ? PdgCode(0x11) : PdgCode(-0x11);
3254  } else {
3255  throw std::runtime_error("StringProcess::pdg_map_for_pythia failed.");
3256  }
3257 
3258  return pdg_mapped.get_decimal();
3259 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ getPPosA()

double smash::StringProcess::getPPosA ( )
inline
Returns
forward lightcone momentum incoming particle A in CM-frame [GeV]
See also
PPosA_

Definition at line 1139 of file processstring.h.

1139 { return PPosA_;}

◆ getPNegA()

double smash::StringProcess::getPNegA ( )
inline
Returns
backward lightcone momentum incoming particle Af in CM-frame [GeV]
See also
PNegA_

Definition at line 1145 of file processstring.h.

1145 { return PNegA_;}

◆ getPPosB()

double smash::StringProcess::getPPosB ( )
inline
Returns
forward lightcone momentum incoming particle B in CM-frame [GeV]
See also
PPosB_

Definition at line 1151 of file processstring.h.

1151 { return PPosB_;}

◆ getPnegB()

double smash::StringProcess::getPnegB ( )
inline
Returns
backward lightcone momentum incoming particle B in CM-frame [GeV]
See also
PNegB_

Definition at line 1157 of file processstring.h.

1157 { return PNegB_;}

◆ get_massA()

double smash::StringProcess::get_massA ( )
inline
Returns
mass of incoming particle A [GeV]
See also
massA_

Definition at line 1163 of file processstring.h.

1163 { return massA_;}

◆ get_massB()

double smash::StringProcess::get_massB ( )
inline
Returns
mass of incoming particle B [GeV]
See also
massB_

Definition at line 1169 of file processstring.h.

1169 { return massB_;}

◆ get_sqrts()

double smash::StringProcess::get_sqrts ( )
inline
Returns
sqrt of mandelstam s [GeV]
See also
sqrtsAB_

Definition at line 1175 of file processstring.h.

1175 { return sqrtsAB_;}

◆ get_PDGs()

std::array<PdgCode, 2> smash::StringProcess::get_PDGs ( )
inline
Returns
array with PDG Codes of incoming particles
See also
PDGcodes_

Definition at line 1181 of file processstring.h.

1181 { return PDGcodes_;}

◆ get_plab()

std::array<FourVector, 2> smash::StringProcess::get_plab ( )
inline
Returns
momenta of incoming particles in lab frame [GeV]
See also
plab_

Definition at line 1187 of file processstring.h.

1187 { return plab_;}

◆ get_pcom()

std::array<FourVector, 2> smash::StringProcess::get_pcom ( )
inline
Returns
momenta of incoming particles in center of mass frame [GeV]
See also
pcom_

Definition at line 1193 of file processstring.h.

1193 { return pcom_;}

◆ get_ucom()

FourVector smash::StringProcess::get_ucom ( )
inline
Returns
velocity four vector of the COM in the lab frame
See also
ucomAB_

Definition at line 1199 of file processstring.h.

1199 { return ucomAB_;}

◆ get_vcom()

ThreeVector smash::StringProcess::get_vcom ( )
inline
Returns
velocity three vector of the COM in the lab frame
See also
vcomAB_

Definition at line 1205 of file processstring.h.

1205 { return vcomAB_;}

◆ get_tcoll()

double smash::StringProcess::get_tcoll ( )
inline
Returns
collision time
See also
time_collision_

Definition at line 1211 of file processstring.h.

1211 { return time_collision_;}

Member Data Documentation

◆ PPosA_

double smash::StringProcess::PPosA_
private

forward lightcone momentum p^{+} of incoming particle A in CM-frame [GeV]

Definition at line 51 of file processstring.h.

◆ PPosB_

double smash::StringProcess::PPosB_
private

forward lightcone momentum p^{+} of incoming particle B in CM-frame [GeV]

Definition at line 53 of file processstring.h.

◆ PNegA_

double smash::StringProcess::PNegA_
private

backward lightcone momentum p^{-} of incoming particle A in CM-frame [GeV]

Definition at line 55 of file processstring.h.

◆ PNegB_

double smash::StringProcess::PNegB_
private

backward lightcone momentum p^{-} of incoming particle B in CM-frame [GeV]

Definition at line 57 of file processstring.h.

◆ massA_

double smash::StringProcess::massA_
private

mass of incoming particle A [GeV]

Definition at line 59 of file processstring.h.

◆ massB_

double smash::StringProcess::massB_
private

mass of incoming particle B [GeV]

Definition at line 61 of file processstring.h.

◆ sqrtsAB_

double smash::StringProcess::sqrtsAB_
private

sqrt of Mandelstam variable s of collision [GeV]

Definition at line 63 of file processstring.h.

◆ PDGcodes_

std::array<PdgCode, 2> smash::StringProcess::PDGcodes_
private

PdgCodes of incoming particles.

Definition at line 65 of file processstring.h.

◆ plab_

std::array<FourVector, 2> smash::StringProcess::plab_
private

momenta of incoming particles in the lab frame [GeV]

Definition at line 67 of file processstring.h.

◆ pcom_

std::array<FourVector, 2> smash::StringProcess::pcom_
private

momenta of incoming particles in the center of mass frame [GeV]

Definition at line 69 of file processstring.h.

◆ ucomAB_

FourVector smash::StringProcess::ucomAB_
private

velocity four vector of the center of mass in the lab frame

Definition at line 71 of file processstring.h.

◆ vcomAB_

ThreeVector smash::StringProcess::vcomAB_
private

velocity three vector of the center of mass in the lab frame

Definition at line 73 of file processstring.h.

◆ evecBasisAB_

std::array<ThreeVector, 3> smash::StringProcess::evecBasisAB_
private

Orthonormal basis vectors in the center of mass frame, where the 0th one is parallel to momentum of incoming particle A.

Definition at line 78 of file processstring.h.

◆ NpartFinal_

int smash::StringProcess::NpartFinal_
private

total number of final state particles

Definition at line 80 of file processstring.h.

◆ NpartString_

std::array<int, 2> smash::StringProcess::NpartString_
private

number of particles fragmented from strings

Definition at line 82 of file processstring.h.

◆ pmin_gluon_lightcone_

double smash::StringProcess::pmin_gluon_lightcone_
private

the minimum lightcone momentum scale carried by a gluon [GeV]

Definition at line 84 of file processstring.h.

◆ pow_fgluon_beta_

double smash::StringProcess::pow_fgluon_beta_
private

parameter \(\beta\) for the gluon distribution function \( P(x) = x^{-1} (1 - x)^{1 + \beta} \)

Definition at line 89 of file processstring.h.

◆ pow_fquark_alpha_

double smash::StringProcess::pow_fquark_alpha_
private

parameter \(\alpha\) for the quark distribution function \( P(x) = x^{\alpha - 1} (1 - x)^{\beta - 1} \)

Definition at line 94 of file processstring.h.

◆ pow_fquark_beta_

double smash::StringProcess::pow_fquark_beta_
private

parameter \(\beta\) for the quark distribution function \( P(x) = x^{\alpha - 1} (1 - x)^{\beta - 1} \)

Definition at line 99 of file processstring.h.

◆ sigma_qperp_

double smash::StringProcess::sigma_qperp_
private

Transverse momentum spread of the excited strings.

[GeV] Transverse momenta of strings are sampled according to gaussian distribution with width sigma_qperp_

Definition at line 105 of file processstring.h.

◆ stringz_a_leading_

double smash::StringProcess::stringz_a_leading_
private

parameter (StringZ:aLund) for the fragmentation function of leading baryon in soft non-diffractive string processes

Definition at line 110 of file processstring.h.

◆ stringz_b_leading_

double smash::StringProcess::stringz_b_leading_
private

parameter (StringZ:bLund) for the fragmentation function of leading baryon in soft non-diffractive string processes

Definition at line 115 of file processstring.h.

◆ stringz_a_produce_

double smash::StringProcess::stringz_a_produce_
private

parameter (StringZ:aLund) for the fragmentation function of other (produced) hadrons in soft non-diffractive string processes

Definition at line 120 of file processstring.h.

◆ stringz_b_produce_

double smash::StringProcess::stringz_b_produce_
private

parameter (StringZ:bLund) for the fragmentation function of other (produced) hadrons in soft non-diffractive string processes

Definition at line 125 of file processstring.h.

◆ kappa_tension_string_

double smash::StringProcess::kappa_tension_string_
private

string tension [GeV/fm]

Definition at line 127 of file processstring.h.

◆ additional_xsec_supp_

double smash::StringProcess::additional_xsec_supp_
private

additional cross-section suppression factor to take coherence effect into account.

Definition at line 132 of file processstring.h.

◆ time_formation_const_

double smash::StringProcess::time_formation_const_
private

constant proper time in the case of constant formation time [fm]

Definition at line 134 of file processstring.h.

◆ soft_t_form_

double smash::StringProcess::soft_t_form_
private

factor to be multiplied to formation times in soft strings

Definition at line 136 of file processstring.h.

◆ time_collision_

double smash::StringProcess::time_collision_
private

time of collision in the computational frame [fm]

Definition at line 138 of file processstring.h.

◆ mass_dependent_formation_times_

bool smash::StringProcess::mass_dependent_formation_times_
private

Whether the formation time should depend on the mass of the fragment according to Andersson:1983ia [2] eq.

2.45:

\( \tau = \sqrt{2}\frac{m}{\kappa} \)

The formation time and position is not calculated directly using the yoyo model because the spacetime rapidity where a string fragment forms is not equal to the fragment's momentum space rapidity. This cannot be easily combined with possible interactions before the formation time.

Definition at line 150 of file processstring.h.

◆ prob_proton_to_d_uu_

double smash::StringProcess::prob_proton_to_d_uu_
private

Probability of splitting a nucleon into the quark flavour it has only once and a diquark it has twice.

Definition at line 155 of file processstring.h.

◆ separate_fragment_baryon_

bool smash::StringProcess::separate_fragment_baryon_
private

Whether to use a separate fragmentation function for leading baryons.

Definition at line 158 of file processstring.h.

◆ pythia_parton_initialized_

bool smash::StringProcess::pythia_parton_initialized_ = false
private

Remembers if Pythia is initialized or not.

Definition at line 160 of file processstring.h.

◆ final_state_

ParticleList smash::StringProcess::final_state_
private

final state array which must be accessed after the collision

Definition at line 166 of file processstring.h.

◆ pythia_parton_

std::unique_ptr<Pythia8::Pythia> smash::StringProcess::pythia_parton_
private

PYTHIA object used in hard string routine.

Definition at line 169 of file processstring.h.

◆ pythia_hadron_

std::unique_ptr<Pythia8::Pythia> smash::StringProcess::pythia_hadron_
private

PYTHIA object used in fragmentation.

Definition at line 172 of file processstring.h.

◆ pythia_sigmatot_

Pythia8::SigmaTotal smash::StringProcess::pythia_sigmatot_
private

An object to compute cross-sections.

Definition at line 175 of file processstring.h.

◆ pythia_stringflav_

Pythia8::StringFlav smash::StringProcess::pythia_stringflav_
private

An object for the flavor selection in string fragmentation in the case of separate fragmentation function for leading baryon.

Definition at line 181 of file processstring.h.

◆ event_intermediate_

Pythia8::Event smash::StringProcess::event_intermediate_
private

event record for intermediate partonic state in the hard string routine

Definition at line 187 of file processstring.h.


The documentation for this class was generated from the following files:
smash::StringProcess::NpartString_
std::array< int, 2 > NpartString_
number of particles fragmented from strings
Definition: processstring.h:82
smash::StringProcess::NpartFinal_
int NpartFinal_
total number of final state particles
Definition: processstring.h:80
smash::random::normal
double normal(const T &mean, const T &sigma)
Returns a random number drawn from a normal distribution.
Definition: random.h:250
smash::StringProcess::evecBasisAB_
std::array< ThreeVector, 3 > evecBasisAB_
Orthonormal basis vectors in the center of mass frame, where the 0th one is parallel to momentum of i...
Definition: processstring.h:78
smash::LOutput
static constexpr int LOutput
Definition: oscaroutput.cc:25
smash::StringProcess::stringz_b_produce_
double stringz_b_produce_
parameter (StringZ:bLund) for the fragmentation function of other (produced) hadrons in soft non-diff...
Definition: processstring.h:125
smash::StringProcess::append_final_state
int append_final_state(ParticleList &intermediate_particles, const FourVector &uString, const ThreeVector &evecLong)
compute the formation time and fill the arrays with final-state particles as described in Andersson:1...
Definition: processstring.cc:144
smash::StringProcess::stringz_b_leading_
double stringz_b_leading_
parameter (StringZ:bLund) for the fragmentation function of leading baryon in soft non-diffractive st...
Definition: processstring.h:115
smash::random::beta_a0
T beta_a0(T xmin, T b)
Draws a random number from a beta-distribution with a = 0.
Definition: random.h:351
smash::StringProcess::compose_string_parton
void compose_string_parton(bool find_forward_string, Pythia8::Event &event_intermediate, Pythia8::Event &event_hadronize)
Identify a set of partons, which are connected to form a color-neutral string, from a given PYTHIA ev...
Definition: processstring.cc:1252
smash::StringProcess::massB_
double massB_
mass of incoming particle B [GeV]
Definition: processstring.h:61
smash::StringProcess::make_string_ends
static void make_string_ends(const PdgCode &pdgcode_in, int &idq1, int &idq2, double xi)
make a random selection to determine partonic contents at the string ends.
Definition: processstring.cc:1700
smash::StringProcess::plab_
std::array< FourVector, 2 > plab_
momenta of incoming particles in the lab frame [GeV]
Definition: processstring.h:67
smash::StringProcess::set_Vec4
static Pythia8::Vec4 set_Vec4(double energy, const ThreeVector &mom)
Easy setter of Pythia Vec4 from SMASH.
Definition: processstring.h:844
smash::StringProcess::pythia_sigmatot_
Pythia8::SigmaTotal pythia_sigmatot_
An object to compute cross-sections.
Definition: processstring.h:175
smash::StringProcess::find_leading
static std::pair< int, int > find_leading(int nq1, int nq2, ParticleList &list)
Find the leading string fragments.
Definition: processstring.cc:3175
smash::StringProcess::pcom_
std::array< FourVector, 2 > pcom_
momenta of incoming particles in the center of mass frame [GeV]
Definition: processstring.h:69
smash::StringProcess::sqrtsAB_
double sqrtsAB_
sqrt of Mandelstam variable s of collision [GeV]
Definition: processstring.h:63
smash::StringProcess::prob_proton_to_d_uu_
double prob_proton_to_d_uu_
Probability of splitting a nucleon into the quark flavour it has only once and a diquark it has twice...
Definition: processstring.h:155
smash::StringProcess::separate_fragment_baryon_
bool separate_fragment_baryon_
Whether to use a separate fragmentation function for leading baryons.
Definition: processstring.h:158
smash::StringProcess::find_total_number_constituent
void find_total_number_constituent(Pythia8::Event &event_intermediate, std::array< int, 5 > &nquark_total, std::array< int, 5 > &nantiq_total)
Compute how many quarks and antiquarks we have in the system, and update the correspoing arrays with ...
Definition: processstring.cc:875
smash::small_number
constexpr double small_number
Physical error tolerance.
Definition: constants.h:48
smash::StringProcess::rearrange_excess
void rearrange_excess(std::array< int, 5 > &nquark_total, std::array< std::array< int, 5 >, 2 > &excess_quark, std::array< std::array< int, 5 >, 2 > &excess_antiq)
Take total number of quarks and check if the system has enough constituents that need to be converted...
Definition: processstring.cc:1037
smash::StringProcess::replace_constituent
void replace_constituent(Pythia8::Particle &particle, std::array< int, 5 > &excess_constituent)
Convert a partonic PYTHIA particle into the desired species and update the excess of constituents.
Definition: processstring.cc:790
smash::StringProcess::time_formation_const_
double time_formation_const_
constant proper time in the case of constant formation time [fm]
Definition: processstring.h:134
smash::StringProcess::pythia_hadron_
std::unique_ptr< Pythia8::Pythia > pythia_hadron_
PYTHIA object used in fragmentation.
Definition: processstring.h:172
smash::StringProcess::pythia_parton_initialized_
bool pythia_parton_initialized_
Remembers if Pythia is initialized or not.
Definition: processstring.h:160
smash::random::uniform_int
T uniform_int(T min, T max)
Definition: random.h:100
smash::StringProcess::set_mass_and_direction_2strings
bool set_mass_and_direction_2strings(const std::array< std::array< int, 2 >, 2 > &quarks, const std::array< FourVector, 2 > &pstr_com, std::array< double, 2 > &m_str, std::array< ThreeVector, 2 > &evec_str)
Determine string masses and directions in which strings are stretched.
Definition: processstring.cc:311
smash::logg
std::array< einhard::Logger<>, std::tuple_size< LogArea::AreaTuple >::value > logg
An array that stores all pre-configured Logger objects.
Definition: logging.cc:39
smash::random::beta
T beta(T a, T b)
Draws a random number from a beta-distribution, where probability density of is .
Definition: random.h:329
smash::StringProcess::PNegA_
double PNegA_
backward lightcone momentum p^{-} of incoming particle A in CM-frame [GeV]
Definition: processstring.h:55
smash::StringProcess::pmin_gluon_lightcone_
double pmin_gluon_lightcone_
the minimum lightcone momentum scale carried by a gluon [GeV]
Definition: processstring.h:84
smash::StringProcess::soft_t_form_
double soft_t_form_
factor to be multiplied to formation times in soft strings
Definition: processstring.h:136
smash::StringProcess::PDGcodes_
std::array< PdgCode, 2 > PDGcodes_
PdgCodes of incoming particles.
Definition: processstring.h:65
smash::pCM
T pCM(const T sqrts, const T mass_a, const T mass_b) noexcept
Definition: kinematics.h:79
smash::really_small
constexpr double really_small
Numerical error tolerance.
Definition: constants.h:37
smash::ParticleType::find
static const ParticleType & find(PdgCode pdgcode)
Returns the ParticleType object for the given pdgcode.
Definition: particletype.cc:105
smash::StringProcess::PPosB_
double PPosB_
forward lightcone momentum p^{+} of incoming particle B in CM-frame [GeV]
Definition: processstring.h:53
smash::StringProcess::compute_incoming_lightcone_momenta
void compute_incoming_lightcone_momenta()
compute the lightcone momenta of incoming particles where the longitudinal direction is set to be sam...
Definition: processstring.cc:1664
smash::StringProcess::shift_rapidity_event
void shift_rapidity_event(Pythia8::Event &event, std::array< ThreeVector, 3 > &evec_basis, double factor_yrapid, double diff_yrapid)
Shift the momentum rapidity of all particles in a given event record.
Definition: processstring.h:1028
smash::StringProcess::quarks_from_diquark
static void quarks_from_diquark(int diquark, int &q1, int &q2, int &deg_spin)
find two quarks from a diquark.
Definition: processstring.cc:1671
smash::StringProcess::fragment_string
int fragment_string(int idq1, int idq2, double mString, ThreeVector &evecLong, bool flip_string_ends, bool separate_fragment_baryon, ParticleList &intermediate_particles)
perform string fragmentation to determine species and momenta of hadrons by implementing PYTHIA 8....
Definition: processstring.cc:1748
smash::StringProcess::diquark_from_quarks
static int diquark_from_quarks(int q1, int q2)
Construct diquark from two quarks.
Definition: processstring.cc:1687
smash::StringProcess::assign_scaling_factor
static void assign_scaling_factor(int nquark, ParticleData &data, double suppression_factor)
Assign a cross section scaling factor to the given particle.
Definition: processstring.cc:3160
smash::StringProcess::make_orthonormal_basis
static void make_orthonormal_basis(ThreeVector &evec_polar, std::array< ThreeVector, 3 > &evec_basis)
compute three orthonormal basis vectors from unit vector in the longitudinal direction
Definition: processstring.cc:1615
smash::StringProcess::event_intermediate_
Pythia8::Event event_intermediate_
event record for intermediate partonic state in the hard string routine
Definition: processstring.h:187
smash::StringProcess::pythia_parton_
std::unique_ptr< Pythia8::Pythia > pythia_parton_
PYTHIA object used in hard string routine.
Definition: processstring.h:169
smash::LPythia
static constexpr int LPythia
Definition: processstring.h:25
smash::StringProcess::find_junction_leg
void find_junction_leg(bool sign_color, std::vector< int > &col, Pythia8::Event &event_intermediate, Pythia8::Event &event_hadronize)
Identify partons, which are associated with junction legs, from a given PYTHIA event record.
Definition: processstring.cc:1442
smash::StringProcess::mass_dependent_formation_times_
bool mass_dependent_formation_times_
Whether the formation time should depend on the mass of the fragment according to Andersson:1983ia e...
Definition: processstring.h:150
smash::StringProcess::get_index_forward
int get_index_forward(bool find_forward, int np_end, Pythia8::Event &event)
Obtain index of the most forward or backward particle in a given PYTHIA event record.
Definition: processstring.h:747
smash::StringProcess::pdg_map_for_pythia
static int pdg_map_for_pythia(PdgCode &pdg)
Take pdg code and map onto particle specie which can be handled by PYTHIA.
Definition: processstring.cc:3239
smash::StringProcess::PNegB_
double PNegB_
backward lightcone momentum p^{-} of incoming particle B in CM-frame [GeV]
Definition: processstring.h:57
smash::StringProcess::convert_KaonLS
static void convert_KaonLS(int &pythia_id)
convert Kaon-L or Kaon-S into K0 or Anti-K0
Definition: processstring.h:806
smash::StringProcess::assign_all_scaling_factors
static void assign_all_scaling_factors(int baryon_string, ParticleList &outgoing_particles, const ThreeVector &evecLong, double suppression_factor)
Assign a cross section scaling factor to all outgoing particles.
Definition: processstring.cc:3192
smash::StringProcess::pow_fquark_beta_
double pow_fquark_beta_
parameter for the quark distribution function
Definition: processstring.h:99
smash::FourVector::velocity
ThreeVector velocity() const
Get the velocity (3-vector divided by zero component).
Definition: fourvector.h:323
smash::StringProcess::stringz_a_produce_
double stringz_a_produce_
parameter (StringZ:aLund) for the fragmentation function of other (produced) hadrons in soft non-diff...
Definition: processstring.h:120
smash::StringProcess::find_excess_constituent
static void find_excess_constituent(PdgCode &pdg_actual, PdgCode &pdg_mapped, std::array< int, 5 > &excess_quark, std::array< int, 5 > &excess_antiq)
Compare the valence quark contents of the actual and mapped hadrons and evaluate how many more consti...
Definition: processstring.cc:756
smash::StringProcess::sigma_qperp_
double sigma_qperp_
Transverse momentum spread of the excited strings.
Definition: processstring.h:105
smash::StringProcess::common_setup_pythia
void common_setup_pythia(Pythia8::Pythia *pythia_in, double strange_supp, double diquark_supp, double popcorn_rate, double stringz_a, double stringz_b, double string_sigma_T)
Common setup of PYTHIA objects for soft and hard string routines.
Definition: processstring.cc:80
smash::StringProcess::splitting_gluon_qqbar
bool splitting_gluon_qqbar(Pythia8::Event &event_intermediate, std::array< int, 5 > &nquark_total, std::array< int, 5 > &nantiq_total, bool sign_constituent, std::array< std::array< int, 5 >, 2 > &excess_constituent)
Take total number of quarks and check if the system has enough constituents that need to be converted...
Definition: processstring.cc:904
smash::StringProcess::ucomAB_
FourVector ucomAB_
velocity four vector of the center of mass in the lab frame
Definition: processstring.h:71
smash::pow_int
constexpr T pow_int(const T base, unsigned const exponent)
Efficient template for calculating integer powers using squaring.
Definition: pow.h:23
smash::StringProcess::reorient
static FourVector reorient(Pythia8::Particle &particle, std::array< ThreeVector, 3 > &evec_basis)
compute the four-momentum properly oriented in the lab frame.
Definition: processstring.h:859
smash::random::power
T power(T n, T xMin, T xMax)
Draws a random number according to a power-law distribution ~ x^n.
Definition: random.h:203
smash::StringProcess::sample_zLund
static double sample_zLund(double a, double b, double mTrn)
Sample lightcone momentum fraction according to the LUND fragmentation function.
Definition: processstring.cc:2829
smash::StringProcess::pythia_stringflav_
Pythia8::StringFlav pythia_stringflav_
An object for the flavor selection in string fragmentation in the case of separate fragmentation func...
Definition: processstring.h:181
smash::StringProcess::additional_xsec_supp_
double additional_xsec_supp_
additional cross-section suppression factor to take coherence effect into account.
Definition: processstring.h:132
smash::StringProcess::make_final_state_2strings
bool make_final_state_2strings(const std::array< std::array< int, 2 >, 2 > &quarks, const std::array< FourVector, 2 > &pstr_com, const std::array< double, 2 > &m_str, const std::array< ThreeVector, 2 > &evec_str, bool flip_string_ends, bool separate_fragment_baryon)
Prepare kinematics of two strings, fragment them and append to final_state.
Definition: processstring.cc:348
smash::StringProcess::remake_kinematics_fragments
bool remake_kinematics_fragments(Pythia8::Event &event_fragments, std::array< ThreeVector, 3 > &evec_basis, double ppos_string, double pneg_string, double QTrx_string, double QTry_string, double QTrx_add_pos, double QTry_add_pos, double QTrx_add_neg, double QTry_add_neg)
Definition: processstring.cc:2861
smash::StringProcess::append_intermediate_list
static bool append_intermediate_list(int pdgid, FourVector momentum, ParticleList &intermediate_particles)
append new particle from PYTHIA to a specific particle list
Definition: processstring.h:792
smash::StringProcess::compose_string_junction
void compose_string_junction(bool &find_forward_string, Pythia8::Event &event_intermediate, Pythia8::Event &event_hadronize)
Identify a set of partons and junction(s), which are connected to form a color-neutral string,...
Definition: processstring.cc:1339
smash::StringProcess::stringz_a_leading_
double stringz_a_leading_
parameter (StringZ:aLund) for the fragmentation function of leading baryon in soft non-diffractive st...
Definition: processstring.h:110
smash::StringProcess::time_collision_
double time_collision_
time of collision in the computational frame [fm]
Definition: processstring.h:138
smash::StringProcess::vcomAB_
ThreeVector vcomAB_
velocity three vector of the center of mass in the lab frame
Definition: processstring.h:73
smash::StringProcess::PPosA_
double PPosA_
forward lightcone momentum p^{+} of incoming particle A in CM-frame [GeV]
Definition: processstring.h:51
smash::pdg::p
constexpr int p
Proton.
Definition: pdgcode_constants.h:28
smash::random::uniform
T uniform(T min, T max)
Definition: random.h:88
smash::StringProcess::pow_fgluon_beta_
double pow_fgluon_beta_
parameter for the gluon distribution function
Definition: processstring.h:89
smash::pdg::n
constexpr int n
Neutron.
Definition: pdgcode_constants.h:30
smash::StringProcess::make_lightcone_final_two
bool make_lightcone_final_two(bool separate_fragment_hadron, double ppos_string, double pneg_string, double mTrn_had_forward, double mTrn_had_backward, double &ppos_had_forward, double &ppos_had_backward, double &pneg_had_forward, double &pneg_had_backward)
Determines lightcone momenta of two final hadrons fragmented from a string in the same way as StringF...
Definition: processstring.cc:2764
smash::StringProcess::pow_fquark_alpha_
double pow_fquark_alpha_
parameter for the quark distribution function
Definition: processstring.h:94
smash::StringProcess::kappa_tension_string_
double kappa_tension_string_
string tension [GeV/fm]
Definition: processstring.h:127
smash::pdg::pi_m
constexpr int pi_m
π⁻.
Definition: pdgcode_constants.h:66
smash::StringProcess::restore_constituent
bool restore_constituent(Pythia8::Event &event_intermediate, std::array< std::array< int, 5 >, 2 > &excess_quark, std::array< std::array< int, 5 >, 2 > &excess_antiq)
Take the intermediate partonic state from PYTHIA event with mapped hadrons and convert constituents i...
Definition: processstring.cc:1094
smash::kaon_mass
constexpr double kaon_mass
Kaon mass in GeV.
Definition: constants.h:69
smash::StringProcess::fragment_off_hadron
int fragment_off_hadron(bool from_forward, bool separate_fragment_baryon, std::array< ThreeVector, 3 > &evec_basis, double &ppos_string, double &pneg_string, double &QTrx_string_pos, double &QTrx_string_neg, double &QTry_string_pos, double &QTry_string_neg, Pythia8::FlavContainer &flav_string_pos, Pythia8::FlavContainer &flav_string_neg, std::vector< int > &pdgid_frag, std::vector< FourVector > &momentum_frag)
Fragment one hadron from a given string configuration if the string mass is above threshold (given by...
Definition: processstring.cc:2219
smash::maximum_rndm_seed_in_pythia
constexpr int maximum_rndm_seed_in_pythia
The maximum value of the random seed used in PYTHIA.
Definition: constants.h:116
smash::pion_mass
constexpr double pion_mass
Pion mass in GeV.
Definition: constants.h:62
smash::pdg::pi_p
constexpr int pi_p
π⁺.
Definition: pdgcode_constants.h:62
smash::StringProcess::final_state_
ParticleList final_state_
final state array which must be accessed after the collision
Definition: processstring.h:166
smash::ParticleType::list_all
static const ParticleTypeList & list_all()
Definition: particletype.cc:57
smash::StringProcess::massA_
double massA_
mass of incoming particle A [GeV]
Definition: processstring.h:59
smash::pCM_sqr
T pCM_sqr(const T sqrts, const T mass_a, const T mass_b) noexcept
Definition: kinematics.h:91