Version: SMASH-3.1
smash::StringProcess Class Reference

#include <stringprocess.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 [5], Bleicher:1999xi [10] and subsequent fragmentation according to the LUND/PYTHIA fragmentation scheme Andersson:1983ia [3], Sjostrand:2014zea [52], Bierlich:2022pfr [8].

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 45 of file stringprocess.h.

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, bool use_monash_tune)
 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...
 
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 [49]. 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 [28]. 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 [5], Bleicher:1999xi [10]. More...
 
bool next_NDiffSoft ()
 Soft Non-diffractive process is modelled in accordance with dual-topological approach Capella:1978ig [15]. 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 [5], Bleicher:1999xi [10] 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...
 
void clear_final_state ()
 a function that clears the final state particle list which is used for testing mainly 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 [3]. 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 exploiting PYTHIA 8.3 Andersson:1983ia [3], Sjostrand:2014zea [52], Bierlich:2022pfr [8]. 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 Types

typedef std::map< std::pair< int, int >, std::unique_ptr< Pythia8::Pythia > > pythia_map
 Map containing PYTHIA objects for hard string routines. 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 strange_supp_
 strange quark suppression factor More...
 
double diquark_supp_
 diquark suppression factor More...
 
double popcorn_rate_
 popcorn rate More...
 
double string_sigma_T_
 transverse momentum spread in string fragmentation 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 [3] 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 use_monash_tune_
 Whether to use the monash tune Skands:2014pea [53] for all string processes. More...
 
ParticleList final_state_
 final state array which must be accessed after the collision More...
 
pythia_map hard_map_
 Map object to contain the different pythia objects. 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...
 

Member Typedef Documentation

◆ pythia_map

typedef std::map<std::pair<int, int>, std::unique_ptr<Pythia8::Pythia> > smash::StringProcess::pythia_map
private

Map containing PYTHIA objects for hard string routines.

Particle IDs are used as the keys to obtain the respective object. This was introduced to reduce the amount of Pythia init() calls.

Definition at line 184 of file stringprocess.h.

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,
bool  use_monash_tune 
)

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.
[in]use_monash_tunewhether to use the monash tune for all string processes. This is recommended if one runs smash at LHC energies
See also
StringProcess::common_setup_pythia(Pythia8::Pythia *, double, double, double, double, double)
pythia8302/share/Pythia8/xmldoc/FlavourSelection.xml
pythia8302/share/Pythia8/xmldoc/Fragmentation.xml
pythia8302/share/Pythia8/xmldoc/MasterSwitches.xml
pythia8302/share/Pythia8/xmldoc/MultipartonInteractions.xml

Definition at line 22 of file stringprocess.cc.

30  : pmin_gluon_lightcone_(gluon_pmin),
31  pow_fgluon_beta_(gluon_beta),
32  pow_fquark_alpha_(quark_alpha),
33  pow_fquark_beta_(quark_beta),
34  sigma_qperp_(sigma_perp),
35  stringz_a_leading_(stringz_a_leading),
36  stringz_b_leading_(stringz_b_leading),
37  stringz_a_produce_(stringz_a),
38  stringz_b_produce_(stringz_b),
39  strange_supp_(strange_supp),
40  diquark_supp_(diquark_supp),
41  popcorn_rate_(popcorn_rate),
42  string_sigma_T_(string_sigma_T),
43  kappa_tension_string_(string_tension),
45  time_formation_const_(time_formation),
46  soft_t_form_(factor_t_form),
47  time_collision_(0.),
48  mass_dependent_formation_times_(mass_dependent_formation_times),
49  prob_proton_to_d_uu_(prob_proton_to_d_uu),
50  separate_fragment_baryon_(separate_fragment_baryon),
51  use_monash_tune_(use_monash_tune) {
52  // setup and initialize pythia for fragmentation
53  pythia_hadron_ = std::make_unique<Pythia8::Pythia>(PYTHIA_XML_DIR, false);
54  /* turn off all parton-level processes to implement only hadronization */
55  pythia_hadron_->readString("ProcessLevel:all = off");
56  common_setup_pythia(pythia_hadron_.get(), strange_supp, diquark_supp,
57  popcorn_rate, stringz_a, stringz_b, string_sigma_T);
58 
59  /* initialize PYTHIA */
60  pythia_hadron_->init();
61 
62  /*
63  * The const_cast<type>() function is used to obtain the reference of the
64  * PrivateInfo object in the pythia_hadron_.
65  * This cast is needed since Pythia 8.302 which included a major architecture
66  * change. The Info object of a Pythia object is now private, only a const
67  * reference can be obtained.
68  * In order to reference the PrivateInfo object during initialization, we
69  * cast the const reference to obtain the stored address.
70  */
71  pythia_sigmatot_.initInfoPtr(
72  const_cast<Pythia8::Info &>(pythia_hadron_->info));
73  pythia_sigmatot_.init();
74 
75  pythia_stringflav_.initInfoPtr(
76  const_cast<Pythia8::Info &>(pythia_hadron_->info));
77  pythia_stringflav_.init();
78 
79  event_intermediate_.init("intermediate partons",
80  &pythia_hadron_->particleData);
81 
82  for (int imu = 0; imu < 3; imu++) {
83  evecBasisAB_[imu] = ThreeVector(0., 0., 0.);
84  }
85 
86  final_state_.clear();
87 }
Pythia8::StringFlav pythia_stringflav_
An object for the flavor selection in string fragmentation in the case of separate fragmentation func...
Pythia8::SigmaTotal pythia_sigmatot_
An object to compute cross-sections.
double pow_fgluon_beta_
parameter for the gluon distribution function
Definition: stringprocess.h:87
Pythia8::Event event_intermediate_
event record for intermediate partonic state in the hard string routine
double time_formation_const_
constant proper time in the case of constant formation time [fm]
double pow_fquark_beta_
parameter for the quark distribution function
Definition: stringprocess.h:97
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...
double popcorn_rate_
popcorn rate
double pmin_gluon_lightcone_
the minimum lightcone momentum scale carried by a gluon [GeV]
Definition: stringprocess.h:82
ParticleList final_state_
final state array which must be accessed after the collision
bool use_monash_tune_
Whether to use the monash tune Skands:2014pea for all string processes.
double soft_t_form_
factor to be multiplied to formation times in soft strings
std::unique_ptr< Pythia8::Pythia > pythia_hadron_
PYTHIA object used in fragmentation.
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.
std::array< ThreeVector, 3 > evecBasisAB_
Orthonormal basis vectors in the center of mass frame, where the 0th one is parallel to momentum of i...
Definition: stringprocess.h:76
double string_sigma_T_
transverse momentum spread in string fragmentation
double additional_xsec_supp_
additional cross-section suppression factor to take coherence effect into account.
double strange_supp_
strange quark suppression factor
double kappa_tension_string_
string tension [GeV/fm]
double pow_fquark_alpha_
parameter for the quark distribution function
Definition: stringprocess.h:92
double stringz_b_leading_
parameter (StringZ:bLund) for the fragmentation function of leading baryon in soft non-diffractive st...
bool mass_dependent_formation_times_
Whether the formation time should depend on the mass of the fragment according to Andersson:1983ia e...
double stringz_b_produce_
parameter (StringZ:bLund) for the fragmentation function of other (produced) hadrons in soft non-diff...
double stringz_a_leading_
parameter (StringZ:aLund) for the fragmentation function of leading baryon in soft non-diffractive st...
double sigma_qperp_
Transverse momentum spread of the excited strings.
bool separate_fragment_baryon_
Whether to use a separate fragmentation function for leading baryons.
double time_collision_
time of collision in the computational frame [fm]
double diquark_supp_
diquark suppression factor
double stringz_a_produce_
parameter (StringZ:aLund) for the fragmentation function of other (produced) hadrons in soft non-diff...

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
pythia8302/share/Pythia8/xmldoc/FlavourSelection.xml
pythia8302/share/Pythia8/xmldoc/Fragmentation.xml

Definition at line 89 of file stringprocess.cc.

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

◆ 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 299 of file stringprocess.h.

299  {
300  const int seed_new =
302 
303  pythia_hadron_->rndm.init(seed_new);
304  logg[LPythia].debug("pythia_hadron_ : rndm is initialized with seed ",
305  seed_new);
306  }
std::array< einhard::Logger<>, std::tuple_size< LogArea::AreaTuple >::value > logg
An array that stores all pre-configured Logger objects.
Definition: logging.cc:39
T uniform_int(T min, T max)
Definition: random.h:100
constexpr int maximum_rndm_seed_in_pythia
The maximum value of the random seed used in PYTHIA.
Definition: constants.h:103
static constexpr int LPythia
Definition: stringprocess.h:26

◆ 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 [49].

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 319 of file stringprocess.h.

320  {
321  // This threshold magic is following Pythia. Todo(ryu): take care of this.
322  double sqrts_threshold = 2. * (1. + 1.0e-6);
323  /* In the case of mesons, the corresponding vector meson masses
324  * are used to evaluate the energy threshold. */
325  const int pdg_a_mod =
326  (std::abs(pdg_a) > 1000) ? pdg_a : 10 * (std::abs(pdg_a) / 10) + 3;
327  const int pdg_b_mod =
328  (std::abs(pdg_b) > 1000) ? pdg_b : 10 * (std::abs(pdg_b) / 10) + 3;
329  sqrts_threshold += pythia_hadron_->particleData.m0(pdg_a_mod) +
330  pythia_hadron_->particleData.m0(pdg_b_mod);
331  /* Constant cross-section for sub-processes below threshold equal to
332  * cross-section at the threshold. */
333  if (sqrt_s < sqrts_threshold) {
334  sqrt_s = sqrts_threshold;
335  }
336  pythia_sigmatot_.calc(pdg_a, pdg_b, sqrt_s);
337  return {pythia_sigmatot_.sigmaAX(), pythia_sigmatot_.sigmaXB(),
338  pythia_sigmatot_.sigmaXX()};
339  }

◆ 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 355 of file stringprocess.h.

355  {
356  pmin_gluon_lightcone_ = p_light_cone_min;
357  }

◆ 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 365 of file stringprocess.h.

365 { 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 374 of file stringprocess.h.

374  {
375  pow_fquark_alpha_ = alphapow;
376  pow_fquark_beta_ = betapow;
377  }

◆ 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 382 of file stringprocess.h.

382 { 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 387 of file stringprocess.h.

387  {
388  kappa_tension_string_ = kappa_string;
389  }

◆ 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 213 of file stringprocess.cc.

213  {
214  PDGcodes_[0] = incoming[0].pdgcode();
215  PDGcodes_[1] = incoming[1].pdgcode();
216  massA_ = incoming[0].effective_mass();
217  massB_ = incoming[1].effective_mass();
218 
219  plab_[0] = incoming[0].momentum();
220  plab_[1] = incoming[1].momentum();
221 
222  // compute sqrts and velocity of the center of mass.
223  sqrtsAB_ = (plab_[0] + plab_[1]).abs();
224  ucomAB_ = (plab_[0] + plab_[1]) / sqrtsAB_;
226 
227  pcom_[0] = plab_[0].lorentz_boost(vcomAB_);
228  pcom_[1] = plab_[1].lorentz_boost(vcomAB_);
229 
230  const double pabscomAB = pCM(sqrtsAB_, massA_, massB_);
231  ThreeVector evec_coll = pcom_[0].threevec() / pabscomAB;
233 
235 
236  time_collision_ = tcoll;
237 }
ThreeVector velocity() const
Get the velocity (3-vector divided by zero component).
Definition: fourvector.h:333
std::array< PdgCode, 2 > PDGcodes_
PdgCodes of incoming particles.
Definition: stringprocess.h:63
FourVector ucomAB_
velocity four vector of the center of mass in the lab frame
Definition: stringprocess.h:69
ThreeVector vcomAB_
velocity three vector of the center of mass in the lab frame
Definition: stringprocess.h:71
void compute_incoming_lightcone_momenta()
compute the lightcone momenta of incoming particles where the longitudinal direction is set to be sam...
double sqrtsAB_
sqrt of Mandelstam variable s of collision [GeV]
Definition: stringprocess.h:61
double massA_
mass of incoming particle A [GeV]
Definition: stringprocess.h:57
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
std::array< FourVector, 2 > plab_
momenta of incoming particles in the lab frame [GeV]
Definition: stringprocess.h:65
std::array< FourVector, 2 > pcom_
momenta of incoming particles in the center of mass frame [GeV]
Definition: stringprocess.h:67
double massB_
mass of incoming particle B [GeV]
Definition: stringprocess.h:59
T pCM(const T sqrts, const T mass_a, const T mass_b) noexcept
Definition: kinematics.h:79

◆ 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 1636 of file stringprocess.cc.

1637  {
1638  assert(std::fabs(evec_polar.sqr() - 1.) < really_small);
1639 
1640  if (std::abs(evec_polar.x3()) < (1. - 1.0e-8)) {
1641  double ex, ey, et;
1642  double theta, phi;
1643 
1644  // evec_basis[0] is set to be longitudinal direction
1645  evec_basis[0] = evec_polar;
1646 
1647  theta = std::acos(evec_basis[0].x3());
1648 
1649  ex = evec_basis[0].x1();
1650  ey = evec_basis[0].x2();
1651  et = std::sqrt(ex * ex + ey * ey);
1652  if (ey > 0.) {
1653  phi = std::acos(ex / et);
1654  } else {
1655  phi = -std::acos(ex / et);
1656  }
1657 
1658  /* The transverse plane is spanned
1659  * by evec_basis[1] and evec_basis[2]. */
1660  evec_basis[1].set_x1(std::cos(theta) * std::cos(phi));
1661  evec_basis[1].set_x2(std::cos(theta) * std::sin(phi));
1662  evec_basis[1].set_x3(-std::sin(theta));
1663 
1664  evec_basis[2].set_x1(-std::sin(phi));
1665  evec_basis[2].set_x2(std::cos(phi));
1666  evec_basis[2].set_x3(0.);
1667  } else {
1668  // if evec_polar is very close to the z axis
1669  if (evec_polar.x3() > 0.) {
1670  evec_basis[1] = ThreeVector(1., 0., 0.);
1671  evec_basis[2] = ThreeVector(0., 1., 0.);
1672  evec_basis[0] = ThreeVector(0., 0., 1.);
1673  } else {
1674  evec_basis[1] = ThreeVector(0., 1., 0.);
1675  evec_basis[2] = ThreeVector(1., 0., 0.);
1676  evec_basis[0] = ThreeVector(0., 0., -1.);
1677  }
1678  }
1679 
1680  assert(std::fabs(evec_basis[1] * evec_basis[2]) < really_small);
1681  assert(std::fabs(evec_basis[2] * evec_basis[0]) < really_small);
1682  assert(std::fabs(evec_basis[0] * evec_basis[1]) < really_small);
1683 }
constexpr double really_small
Numerical error tolerance.
Definition: constants.h:37

◆ 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 1685 of file stringprocess.cc.

1685  {
1686  PPosA_ = (pcom_[0].x0() + evecBasisAB_[0] * pcom_[0].threevec()) * M_SQRT1_2;
1687  PNegA_ = (pcom_[0].x0() - evecBasisAB_[0] * pcom_[0].threevec()) * M_SQRT1_2;
1688  PPosB_ = (pcom_[1].x0() + evecBasisAB_[0] * pcom_[1].threevec()) * M_SQRT1_2;
1689  PNegB_ = (pcom_[1].x0() - evecBasisAB_[0] * pcom_[1].threevec()) * M_SQRT1_2;
1690 }
double PNegB_
backward lightcone momentum p^{-} of incoming particle B in CM-frame [GeV]
Definition: stringprocess.h:55
double PPosA_
forward lightcone momentum p^{+} of incoming particle A in CM-frame [GeV]
Definition: stringprocess.h:49
double PNegA_
backward lightcone momentum p^{-} of incoming particle A in CM-frame [GeV]
Definition: stringprocess.h:53
double PPosB_
forward lightcone momentum p^{+} of incoming particle B in CM-frame [GeV]
Definition: stringprocess.h:51

◆ 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 324 of file stringprocess.cc.

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

◆ 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 361 of file stringprocess.cc.

366  {
367  const std::array<FourVector, 2> ustr_com = {pstr_com[0] / m_str[0],
368  pstr_com[1] / m_str[1]};
369  for (int i = 0; i < 2; i++) {
370  ParticleList new_intermediate_particles;
371 
372  // determine direction in which string i is stretched.
373  ThreeVector evec = evec_str[i];
374  // perform fragmentation and add particles to final_state.
375  int nfrag = fragment_string(quarks[i][0], quarks[i][1], m_str[i], evec,
376  flip_string_ends, separate_fragment_baryon,
377  new_intermediate_particles);
378  if (nfrag <= 0) {
379  NpartString_[i] = 0;
380  return false;
381  }
382  NpartString_[i] =
383  append_final_state(new_intermediate_particles, ustr_com[i], evec);
384  assert(nfrag == NpartString_[i]);
385  }
386  if ((NpartString_[0] > 0) && (NpartString_[1] > 0)) {
388  return true;
389  }
390  return false;
391 }
std::array< int, 2 > NpartString_
number of particles fragmented from strings
Definition: stringprocess.h:80
int fragment_string(int idq1, int idq2, double mString, ThreeVector &evecLong, bool flip_string_ends, bool separate_fragment_baryon, ParticleList &intermediate_particles)
perform string fragmentation to determine species and momenta of hadrons by exploiting PYTHIA 8....
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...
int NpartFinal_
total number of final state particles
Definition: stringprocess.h:78

◆ 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 [28].

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 242 of file stringprocess.cc.

242  {
243  NpartFinal_ = 0;
244  NpartString_[0] = 0;
245  NpartString_[1] = 0;
246  final_state_.clear();
247 
248  double massH = is_AB_to_AX ? massA_ : massB_;
249  double mstrMin = is_AB_to_AX ? massB_ : massA_;
250  double mstrMax = sqrtsAB_ - massH;
251 
252  int idqX1, idqX2;
253  double QTrn, QTrx, QTry;
254  double pabscomHX_sqr, massX;
255 
256  // decompose hadron into quarks
257  make_string_ends(is_AB_to_AX ? PDGcodes_[1] : PDGcodes_[0], idqX1, idqX2,
259  // string mass must be larger than threshold set by PYTHIA.
260  mstrMin = pythia_hadron_->particleData.m0(idqX1) +
261  pythia_hadron_->particleData.m0(idqX2);
262  // this threshold cannot be larger than maximum of allowed string mass.
263  if (mstrMin > mstrMax) {
264  return false;
265  }
266  // sample the transverse momentum transfer
267  QTrx = random::normal(0., sigma_qperp_ * M_SQRT1_2);
268  QTry = random::normal(0., sigma_qperp_ * M_SQRT1_2);
269  QTrn = std::sqrt(QTrx * QTrx + QTry * QTry);
270  /* sample the string mass and
271  * evaluate the three-momenta of hadron and string. */
272  massX = random::power(-1.0, mstrMin, mstrMax);
273  pabscomHX_sqr = pCM_sqr(sqrtsAB_, massH, massX);
274  /* magnitude of the three momentum must be larger
275  * than the transverse momentum. */
276  const bool foundPabsX = pabscomHX_sqr > QTrn * QTrn;
277 
278  if (!foundPabsX) {
279  return false;
280  }
281  double sign_direction = is_AB_to_AX ? 1. : -1.;
282  // determine three momentum of the final state hadron
283  const ThreeVector cm_momentum =
284  sign_direction *
285  (evecBasisAB_[0] * std::sqrt(pabscomHX_sqr - QTrn * QTrn) +
286  evecBasisAB_[1] * QTrx + evecBasisAB_[2] * QTry);
287  const FourVector pstrHcom(std::sqrt(pabscomHX_sqr + massH * massH),
288  cm_momentum);
289  const FourVector pstrXcom(std::sqrt(pabscomHX_sqr + massX * massX),
290  -cm_momentum);
291 
292  const FourVector ustrXcom = pstrXcom / massX;
293  /* determine direction in which the string is stretched.
294  * this is set to be same with the the collision axis
295  * in the center of mass frame. */
296  const ThreeVector threeMomentum =
297  is_AB_to_AX ? pcom_[1].threevec() : pcom_[0].threevec();
298  const FourVector pnull = FourVector(threeMomentum.abs(), threeMomentum);
299  const FourVector prs = pnull.lorentz_boost(ustrXcom.velocity());
300  ThreeVector evec = prs.threevec() / prs.threevec().abs();
301  // perform fragmentation and add particles to final_state.
302  ParticleList new_intermediate_particles;
303  int nfrag = fragment_string(idqX1, idqX2, massX, evec, true, false,
304  new_intermediate_particles);
305  if (nfrag < 1) {
306  NpartString_[0] = 0;
307  return false;
308  }
309  NpartString_[0] =
310  append_final_state(new_intermediate_particles, ustrXcom, evec);
311 
312  NpartString_[1] = 1;
313  PdgCode hadron_code = is_AB_to_AX ? PDGcodes_[0] : PDGcodes_[1];
314  ParticleData new_particle(ParticleType::find(hadron_code));
315  new_particle.set_4momentum(pstrHcom);
316  new_particle.set_cross_section_scaling_factor(1.);
317  new_particle.set_formation_time(time_collision_);
318  final_state_.push_back(new_particle);
319 
321  return true;
322 }
static const ParticleType & find(PdgCode pdgcode)
Returns the ParticleType object for the given pdgcode.
Definition: particletype.cc:99
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.
T power(T n, T xMin, T xMax)
Draws a random number according to a power-law distribution ~ x^n.
Definition: random.h:203
double normal(const T &mean, const T &sigma)
Returns a random number drawn from a normal distribution.
Definition: random.h:250
T pCM_sqr(const T sqrts, const T mass_a, const T mass_b) noexcept
Definition: kinematics.h:91

◆ 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 [5], Bleicher:1999xi [10].

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

Returns
whether the process is successfully implemented.

Definition at line 394 of file stringprocess.cc.

394  {
395  NpartFinal_ = 0;
396  NpartString_[0] = 0;
397  NpartString_[1] = 0;
398  final_state_.clear();
399 
400  std::array<std::array<int, 2>, 2> quarks;
401  std::array<FourVector, 2> pstr_com;
402  std::array<double, 2> m_str;
403  std::array<ThreeVector, 2> evec_str;
404  ThreeVector threeMomentum;
405 
406  // decompose hadron into quark (and diquark) contents
407  make_string_ends(PDGcodes_[0], quarks[0][0], quarks[0][1],
409  make_string_ends(PDGcodes_[1], quarks[1][0], quarks[1][1],
411  // sample the lightcone momentum fraction carried by gluons
412  const double xmin_gluon_fraction = pmin_gluon_lightcone_ / sqrtsAB_;
413  const double xfracA =
414  random::beta_a0(xmin_gluon_fraction, pow_fgluon_beta_ + 1.);
415  const double xfracB =
416  random::beta_a0(xmin_gluon_fraction, pow_fgluon_beta_ + 1.);
417  // sample the transverse momentum transfer
418  const double QTrx = random::normal(0., sigma_qperp_ * M_SQRT1_2);
419  const double QTry = random::normal(0., sigma_qperp_ * M_SQRT1_2);
420  const double QTrn = std::sqrt(QTrx * QTrx + QTry * QTry);
421  // evaluate the lightcone momentum transfer
422  const double QPos = -QTrn * QTrn / (2. * xfracB * PNegB_);
423  const double QNeg = QTrn * QTrn / (2. * xfracA * PPosA_);
424  // compute four-momentum of string 1
425  threeMomentum =
426  evecBasisAB_[0] * (PPosA_ + QPos - PNegA_ - QNeg) * M_SQRT1_2 +
427  evecBasisAB_[1] * QTrx + evecBasisAB_[2] * QTry;
428  pstr_com[0] =
429  FourVector((PPosA_ + QPos + PNegA_ + QNeg) * M_SQRT1_2, threeMomentum);
430  // compute four-momentum of string 2
431  threeMomentum =
432  evecBasisAB_[0] * (PPosB_ - QPos - PNegB_ + QNeg) * M_SQRT1_2 -
433  evecBasisAB_[1] * QTrx - evecBasisAB_[2] * QTry;
434  pstr_com[1] =
435  FourVector((PPosB_ - QPos + PNegB_ - QNeg) * M_SQRT1_2, threeMomentum);
436 
437  const bool found_masses =
438  set_mass_and_direction_2strings(quarks, pstr_com, m_str, evec_str);
439  if (!found_masses) {
440  return false;
441  }
442  const bool flip_string_ends = true;
443  const bool success = make_final_state_2strings(
444  quarks, pstr_com, m_str, evec_str, flip_string_ends, false);
445  return success;
446 }
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.
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.
T beta_a0(T xmin, T b)
Draws a random number from a beta-distribution with a = 0.
Definition: random.h:351

◆ next_NDiffSoft()

bool smash::StringProcess::next_NDiffSoft ( )

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

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 [5], Bleicher:1999xi [10].

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

Definition at line 449 of file stringprocess.cc.

449  {
450  NpartFinal_ = 0;
451  NpartString_[0] = 0;
452  NpartString_[1] = 0;
453  final_state_.clear();
454 
455  std::array<std::array<int, 2>, 2> quarks;
456  std::array<FourVector, 2> pstr_com;
457  std::array<double, 2> m_str;
458  std::array<ThreeVector, 2> evec_str;
459 
460  // decompose hadron into quark (and diquark) contents
461  int idqA1, idqA2, idqB1, idqB2;
464 
465  const int bar_a = PDGcodes_[0].baryon_number(),
466  bar_b = PDGcodes_[1].baryon_number();
467  if (bar_a == 1 || // baryon-baryon, baryon-meson, baryon-antibaryon
468  (bar_a == 0 && bar_b == 1) || // meson-baryon
469  (bar_a == 0 && bar_b == 0)) { // meson-meson
470  quarks[0][0] = idqB1;
471  quarks[0][1] = idqA2;
472  quarks[1][0] = idqA1;
473  quarks[1][1] = idqB2;
474  } else if (((bar_a == 0) && (bar_b == -1)) || // meson-antibaryon
475  (bar_a == -1)) { // antibaryon-baryon, antibaryon-meson,
476  // antibaryon-antibaryon
477  quarks[0][0] = idqA1;
478  quarks[0][1] = idqB2;
479  quarks[1][0] = idqB1;
480  quarks[1][1] = idqA2;
481  } else {
482  std::stringstream ss;
483  ss << " StringProcess::next_NDiff : baryonA = " << bar_a
484  << ", baryonB = " << bar_b;
485  throw std::runtime_error(ss.str());
486  }
487  // sample the lightcone momentum fraction carried by quarks
488  const double xfracA = random::beta(pow_fquark_alpha_, pow_fquark_beta_);
489  const double xfracB = random::beta(pow_fquark_alpha_, pow_fquark_beta_);
490  // sample the transverse momentum transfer
491  const double QTrx = random::normal(0., sigma_qperp_ * M_SQRT1_2);
492  const double QTry = random::normal(0., sigma_qperp_ * M_SQRT1_2);
493  const double QTrn = std::sqrt(QTrx * QTrx + QTry * QTry);
494  // evaluate the lightcone momentum transfer
495  const double QPos = -QTrn * QTrn / (2. * xfracB * PNegB_);
496  const double QNeg = QTrn * QTrn / (2. * xfracA * PPosA_);
497  const double dPPos = -xfracA * PPosA_ - QPos;
498  const double dPNeg = xfracB * PNegB_ - QNeg;
499  // compute four-momentum of string 1
500  ThreeVector threeMomentum =
501  evecBasisAB_[0] * (PPosA_ + dPPos - PNegA_ - dPNeg) * M_SQRT1_2 +
502  evecBasisAB_[1] * QTrx + evecBasisAB_[2] * QTry;
503  pstr_com[0] =
504  FourVector((PPosA_ + dPPos + PNegA_ + dPNeg) * M_SQRT1_2, threeMomentum);
505  m_str[0] = pstr_com[0].sqr();
506  // compute four-momentum of string 2
507  threeMomentum =
508  evecBasisAB_[0] * (PPosB_ - dPPos - PNegB_ + dPNeg) * M_SQRT1_2 -
509  evecBasisAB_[1] * QTrx - evecBasisAB_[2] * QTry;
510  pstr_com[1] =
511  FourVector((PPosB_ - dPPos + PNegB_ - dPNeg) * M_SQRT1_2, threeMomentum);
512 
513  const bool found_masses =
514  set_mass_and_direction_2strings(quarks, pstr_com, m_str, evec_str);
515  if (!found_masses) {
516  return false;
517  }
518  const bool flip_string_ends = false;
519  const bool success =
520  make_final_state_2strings(quarks, pstr_com, m_str, evec_str,
521  flip_string_ends, separate_fragment_baryon_);
522  return success;
523 }
T beta(T a, T b)
Draws a random number from a beta-distribution, where probability density of is .
Definition: random.h:329

◆ 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 526 of file stringprocess.cc.

526  {
527  NpartFinal_ = 0;
528  final_state_.clear();
529 
530  logg[LPythia].debug("Hard non-diff. with ", PDGcodes_[0], " + ", PDGcodes_[1],
531  " at CM energy [GeV] ", sqrtsAB_);
532 
533  std::array<int, 2> pdg_for_pythia;
534  std::array<std::array<int, 5>, 2> excess_quark;
535  std::array<std::array<int, 5>, 2> excess_antiq;
536  for (int i = 0; i < 2; i++) {
537  for (int j = 0; j < 5; j++) {
538  excess_quark[i][j] = 0;
539  excess_antiq[i][j] = 0;
540  }
541 
542  // get PDG id used in PYTHIA event generation
543  pdg_for_pythia[i] = pdg_map_for_pythia(PDGcodes_[i]);
544  logg[LPythia].debug(" incoming particle ", i, " : ", PDGcodes_[i],
545  " is mapped onto ", pdg_for_pythia[i]);
546 
547  PdgCode pdgcode_for_pythia(std::to_string(pdg_for_pythia[i]));
548  /* evaluate how many more constituents incoming hadron has
549  * compared to the mapped one. */
550  find_excess_constituent(PDGcodes_[i], pdgcode_for_pythia, excess_quark[i],
551  excess_antiq[i]);
552  logg[LPythia].debug(" excess_quark[", i, "] = (", excess_quark[i][0],
553  ", ", excess_quark[i][1], ", ", excess_quark[i][2],
554  ", ", excess_quark[i][3], ", ", excess_quark[i][4],
555  ")");
556  logg[LPythia].debug(" excess_antiq[", i, "] = (", excess_antiq[i][0],
557  ", ", excess_antiq[i][1], ", ", excess_antiq[i][2],
558  ", ", excess_antiq[i][3], ", ", excess_antiq[i][4],
559  ")");
560  }
561 
562  std::pair<int, int> idAB{pdg_for_pythia[0], pdg_for_pythia[1]};
563 
564  // If an entry for the calculated particle IDs does not exist, create one and
565  // initialize it accordingly
566  if (hard_map_.count(idAB) == 0) {
567  hard_map_[idAB] = std::make_unique<Pythia8::Pythia>(PYTHIA_XML_DIR, false);
568  hard_map_[idAB]->readString("SoftQCD:nonDiffractive = on");
569  hard_map_[idAB]->readString("MultipartonInteractions:pTmin = 1.5");
570  hard_map_[idAB]->readString("HadronLevel:all = off");
571 
575 
576  hard_map_[idAB]->settings.flag("Beams:allowVariableEnergy", true);
577 
578  hard_map_[idAB]->settings.mode("Beams:idA", idAB.first);
579  hard_map_[idAB]->settings.mode("Beams:idB", idAB.second);
580  hard_map_[idAB]->settings.parm("Beams:eCM", sqrtsAB_);
581 
582  logg[LPythia].debug("Pythia object initialized with ", pdg_for_pythia[0],
583  " + ", pdg_for_pythia[1], " at CM energy [GeV] ",
584  sqrtsAB_);
585 
586  if (!hard_map_[idAB]->init()) {
587  throw std::runtime_error("Pythia failed to initialize.");
588  }
589  }
590 
591  const int seed_new = random::uniform_int(1, maximum_rndm_seed_in_pythia);
592  hard_map_[idAB]->rndm.init(seed_new);
593  logg[LPythia].debug("hard_map_[", idAB.first, "][", idAB.second,
594  "] : rndm is initialized with seed ", seed_new);
595 
596  // Change the energy using the Pythia 8.302+ feature
597 
598  // Short notation for Pythia event
599  Pythia8::Event &event_hadron = pythia_hadron_->event;
600  logg[LPythia].debug("Pythia hard event created");
601  // we update the collision energy in the CM frame
602  hard_map_[idAB]->setKinematics(sqrtsAB_);
603  bool final_state_success = hard_map_[idAB]->next();
604  logg[LPythia].debug("Pythia final state computed, success = ",
605  final_state_success);
606  if (!final_state_success) {
607  return false;
608  }
609 
610  ParticleList new_intermediate_particles;
611  ParticleList new_non_hadron_particles;
612 
613  Pythia8::Vec4 pSum = 0.;
614  event_intermediate_.reset();
615  /* Update the partonic intermediate state from PYTHIA output.
616  * Note that hadronization will be performed separately,
617  * after identification of strings and replacement of constituents. */
618  for (int i = 0; i < hard_map_[idAB]->event.size(); i++) {
619  if (hard_map_[idAB]->event[i].isFinal()) {
620  const int pdgid = hard_map_[idAB]->event[i].id();
621  Pythia8::Vec4 pquark = hard_map_[idAB]->event[i].p();
622  const double mass = hard_map_[idAB]->particleData.m0(pdgid);
623 
624  const int status = hard_map_[idAB]->event[i].status();
625  const int color = hard_map_[idAB]->event[i].col();
626  const int anticolor = hard_map_[idAB]->event[i].acol();
627 
628  pSum += pquark;
629  event_intermediate_.append(pdgid, status, color, anticolor, pquark, mass);
630  }
631  }
632  // add junctions to the intermediate state if there is any.
633  event_intermediate_.clearJunctions();
634  for (int i = 0; i < hard_map_[idAB]->event.sizeJunction(); i++) {
635  const int kind = hard_map_[idAB]->event.kindJunction(i);
636  std::array<int, 3> col;
637  for (int j = 0; j < 3; j++) {
638  col[j] = hard_map_[idAB]->event.colJunction(i, j);
639  }
640  event_intermediate_.appendJunction(kind, col[0], col[1], col[2]);
641  }
642  /* The zeroth entry of event record is supposed to have the information
643  * on the whole system. Specify the total momentum and invariant mass. */
644  event_intermediate_[0].p(pSum);
645  event_intermediate_[0].m(pSum.mCalc());
646 
647  /* Replace quark constituents according to the excess of valence quarks
648  * and then rescale momenta of partons by constant factor
649  * to fulfill the energy-momentum conservation. */
650  bool correct_constituents =
651  restore_constituent(event_intermediate_, excess_quark, excess_antiq);
652  if (!correct_constituents) {
653  logg[LPythia].debug("failed to find correct partonic constituents.");
654  return false;
655  }
656 
657  int npart = event_intermediate_.size();
658  int ipart = 0;
659  while (ipart < npart) {
660  const int pdgid = event_intermediate_[ipart].id();
661  if (event_intermediate_[ipart].isFinal() &&
662  !event_intermediate_[ipart].isParton() &&
663  !hard_map_[idAB]->particleData.isOctetHadron(pdgid)) {
664  logg[LPythia].debug("PDG ID from Pythia: ", pdgid);
665  FourVector momentum = reorient(event_intermediate_[ipart], evecBasisAB_);
666  logg[LPythia].debug("4-momentum from Pythia: ", momentum);
667  bool found_ptype =
668  append_intermediate_list(pdgid, momentum, new_non_hadron_particles);
669  if (!found_ptype) {
670  logg[LPythia].warn("PDG ID ", pdgid,
671  " does not exist in ParticleType - start over.");
672  final_state_success = false;
673  }
674  event_intermediate_.remove(ipart, ipart);
675  npart -= 1;
676  } else {
677  ipart += 1;
678  }
679  }
680 
681  bool hadronize_success = false;
682  bool find_forward_string = true;
683  logg[LPythia].debug("Hard non-diff: partonic process gives ",
684  event_intermediate_.size(), " partons.");
685  // identify and fragment strings until there is no parton left.
686  while (event_intermediate_.size() > 1) {
687  // dummy event to initialize the internal variables of PYTHIA.
688  pythia_hadron_->event.reset();
689  if (!pythia_hadron_->next()) {
690  logg[LPythia].debug(" Dummy event in hard string routine failed.");
691  hadronize_success = false;
692  break;
693  }
694 
695  if (event_intermediate_.sizeJunction() > 0) {
696  // identify string from a junction if there is any.
697  compose_string_junction(find_forward_string, event_intermediate_,
698  pythia_hadron_->event);
699  } else {
700  /* identify string from a most forward or backward parton.
701  * if there is no junction. */
702  compose_string_parton(find_forward_string, event_intermediate_,
703  pythia_hadron_->event);
704  }
705 
706  // fragment the (identified) string into hadrons.
707  hadronize_success = pythia_hadron_->forceHadronLevel(false);
708  logg[LPythia].debug("Pythia hadronized, success = ", hadronize_success);
709 
710  new_intermediate_particles.clear();
711  if (hadronize_success) {
712  for (int i = 0; i < event_hadron.size(); i++) {
713  if (event_hadron[i].isFinal()) {
714  int pythia_id = event_hadron[i].id();
715  logg[LPythia].debug("PDG ID from Pythia: ", pythia_id);
716  /* K_short and K_long need to be converted to K0
717  * since SMASH only knows K0 */
718  convert_KaonLS(pythia_id);
719 
720  /* evecBasisAB_[0] is a unit 3-vector in the collision axis,
721  * while evecBasisAB_[1] and evecBasisAB_[2] spans the transverse
722  * plane. Given that PYTHIA assumes z-direction to be the collision
723  * axis, pz from PYTHIA should be the momentum compoment in
724  * evecBasisAB_[0]. px and py are respectively the momentum components
725  * in two transverse directions evecBasisAB_[1] and evecBasisAB_[2].
726  */
727  FourVector momentum = reorient(event_hadron[i], evecBasisAB_);
728  logg[LPythia].debug("4-momentum from Pythia: ", momentum);
729  logg[LPythia].debug("appending the particle ", pythia_id,
730  " to the intermediate particle list.");
731  bool found_ptype = false;
732  if (event_hadron[i].isHadron()) {
733  found_ptype = append_intermediate_list(pythia_id, momentum,
734  new_intermediate_particles);
735  } else {
736  found_ptype = append_intermediate_list(pythia_id, momentum,
737  new_non_hadron_particles);
738  }
739  if (!found_ptype) {
740  logg[LPythia].warn("PDG ID ", pythia_id,
741  " does not exist in ParticleType - start over.");
742  hadronize_success = false;
743  }
744  }
745  }
746  }
747 
748  /* if hadronization is not successful,
749  * reset the event records, return false and then start over. */
750  if (!hadronize_success) {
751  break;
752  }
753 
754  FourVector uString = FourVector(1., 0., 0., 0.);
755  ThreeVector evec = find_forward_string ? evecBasisAB_[0] : -evecBasisAB_[0];
756  int nfrag = append_final_state(new_intermediate_particles, uString, evec);
757  NpartFinal_ += nfrag;
758 
759  find_forward_string = !find_forward_string;
760  }
761 
762  if (hadronize_success) {
763  // add the final state particles, which are not hadron.
764  for (ParticleData data : new_non_hadron_particles) {
765  data.set_cross_section_scaling_factor(1.);
766  data.set_formation_time(time_collision_);
767  final_state_.push_back(data);
768  }
769  } else {
770  final_state_.clear();
771  }
772 
773  return hadronize_success;
774 }
pythia_map hard_map_
Map object to contain the different pythia objects.
static FourVector reorient(Pythia8::Particle &particle, std::array< ThreeVector, 3 > &evec_basis)
compute the four-momentum properly oriented in the lab frame.
static int pdg_map_for_pythia(PdgCode &pdg)
Take pdg code and map onto particle specie which can be handled by PYTHIA.
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...
static void convert_KaonLS(int &pythia_id)
convert Kaon-L or Kaon-S into K0 or Anti-K0
static bool append_intermediate_list(int pdgid, FourVector momentum, ParticleList &intermediate_particles)
append new particle from PYTHIA to a specific particle list
void init(const ParticleList &incoming, double tcoll)
initialization feed intial particles, time of collision and gamma factor of the center of mass.
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...
void compose_string_parton(bool find_forward_string, Pythia8::Event &event_intermediate, Pythia8::Event &event_hadronize)
Identify a set of partons, which are connected to form a color-neutral string, from a given PYTHIA ev...
void 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,...

◆ next_BBbarAnn()

bool smash::StringProcess::next_BBbarAnn ( )

Baryon-antibaryon annihilation process Based on what UrQMD Bass:1998ca [5], Bleicher:1999xi [10] 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 1525 of file stringprocess.cc.

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

◆ 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 776 of file stringprocess.cc.

779  {
780  /* decompose PDG id of the actual hadron and mapped one
781  * to get the valence quark constituents */
782  std::array<int, 3> qcontent_actual = pdg_actual.quark_content();
783  std::array<int, 3> qcontent_mapped = pdg_mapped.quark_content();
784 
785  excess_quark = {0, 0, 0, 0, 0};
786  excess_antiq = {0, 0, 0, 0, 0};
787  for (int i = 0; i < 3; i++) {
788  if (qcontent_actual[i] > 0) { // quark content of the actual hadron
789  int j = qcontent_actual[i] - 1;
790  excess_quark[j] += 1;
791  }
792 
793  if (qcontent_mapped[i] > 0) { // quark content of the mapped hadron
794  int j = qcontent_mapped[i] - 1;
795  excess_quark[j] -= 1;
796  }
797 
798  if (qcontent_actual[i] < 0) { // antiquark content of the actual hadron
799  int j = std::abs(qcontent_actual[i]) - 1;
800  excess_antiq[j] += 1;
801  }
802 
803  if (qcontent_mapped[i] < 0) { // antiquark content of the mapped hadron
804  int j = std::abs(qcontent_mapped[i]) - 1;
805  excess_antiq[j] -= 1;
806  }
807  }
808 }

◆ 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 810 of file stringprocess.cc.

811  {
812  // If the particle is neither quark nor diquark, nothing to do.
813  if (!particle.isQuark() && !particle.isDiquark()) {
814  return;
815  }
816 
817  // If there is no excess of constituents, nothing to do.
818  const std::array<int, 5> excess_null = {0, 0, 0, 0, 0};
819  if (excess_constituent == excess_null) {
820  return;
821  }
822 
823  int nq = 0;
824  std::array<int, 2> pdgid = {0, 0};
825  int spin_deg = 0;
826  int pdgid_new = 0;
827  if (particle.isQuark()) {
828  nq = 1;
829  pdgid[0] = particle.id();
830  } else if (particle.isDiquark()) {
831  nq = 2;
832  quarks_from_diquark(particle.id(), pdgid[0], pdgid[1], spin_deg);
833  }
834 
835  for (int iq = 0; iq < nq; iq++) {
836  int jq = std::abs(pdgid[iq]) - 1;
837  int k_select = 0;
838  std::vector<int> k_found;
839  k_found.clear();
840  // check if the constituent needs to be converted.
841  if (excess_constituent[jq] < 0) {
842  for (int k = 0; k < 5; k++) {
843  // check which specie it can be converted into.
844  if (k != jq && excess_constituent[k] > 0) {
845  k_found.push_back(k);
846  }
847  }
848  }
849 
850  // make a random selection of specie and update the excess of constituent.
851  if (k_found.size() > 0) {
852  const int l =
853  random::uniform_int(0, static_cast<int>(k_found.size()) - 1);
854  k_select = k_found[l];
855  /* flavor jq + 1 is converted into k_select + 1
856  * and excess_constituent is updated. */
857  pdgid[iq] = pdgid[iq] > 0 ? k_select + 1 : -(k_select + 1);
858  excess_constituent[jq] += 1;
859  excess_constituent[k_select] -= 1;
860  }
861  }
862 
863  // determine PDG id of the converted parton.
864  if (particle.isQuark()) {
865  pdgid_new = pdgid[0];
866  } else if (particle.isDiquark()) {
867  if (std::abs(pdgid[0]) < std::abs(pdgid[1])) {
868  std::swap(pdgid[0], pdgid[1]);
869  }
870 
871  pdgid_new = std::abs(pdgid[0]) * 1000 + std::abs(pdgid[1]) * 100;
872  if (std::abs(pdgid[0]) == std::abs(pdgid[1])) {
873  pdgid_new += 3;
874  } else {
875  pdgid_new += spin_deg;
876  }
877 
878  if (particle.id() < 0) {
879  pdgid_new *= -1;
880  }
881  }
882  logg[LPythia].debug(" parton id = ", particle.id(), " is converted to ",
883  pdgid_new);
884 
885  // update the constituent mass and energy.
886  Pythia8::Vec4 pquark = particle.p();
887  double mass_new = pythia_hadron_->particleData.m0(pdgid_new);
888  double e_new = std::sqrt(mass_new * mass_new + pquark.pAbs() * pquark.pAbs());
889  // update the particle object.
890  particle.id(pdgid_new);
891  particle.e(e_new);
892  particle.m(mass_new);
893 }
static void quarks_from_diquark(int diquark, int &q1, int &q2, int &deg_spin)
find two quarks from a diquark.

◆ 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 895 of file stringprocess.cc.

897  {
898  for (int iflav = 0; iflav < 5; iflav++) {
899  nquark_total[iflav] = 0;
900  nantiq_total[iflav] = 0;
901  }
902 
903  for (int ip = 1; ip < event_intermediate.size(); ip++) {
904  if (!event_intermediate[ip].isFinal()) {
905  continue;
906  }
907  const int pdgid = event_intermediate[ip].id();
908  if (pdgid > 0) {
909  // quarks
910  for (int iflav = 0; iflav < 5; iflav++) {
911  nquark_total[iflav] +=
912  pythia_hadron_->particleData.nQuarksInCode(pdgid, iflav + 1);
913  }
914  } else {
915  // antiquarks
916  for (int iflav = 0; iflav < 5; iflav++) {
917  nantiq_total[iflav] += pythia_hadron_->particleData.nQuarksInCode(
918  std::abs(pdgid), iflav + 1);
919  }
920  }
921  }
922 }

◆ 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 924 of file stringprocess.cc.

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

◆ 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 1057 of file stringprocess.cc.

1060  {
1061  for (int iflav = 0; iflav < 5; iflav++) {
1062  /* Find how many constituent will be in the system after
1063  * changing the flavors.
1064  * Note that nquark_total is number of constituent right after
1065  * the pythia event (with mapped incoming hadrons), while the excess
1066  * shows how many constituents we have more or less that nquark_total. */
1067  int nquark_final =
1068  nquark_total[iflav] + excess_quark[0][iflav] + excess_quark[1][iflav];
1069  /* Therefore, nquark_final should not be negative.
1070  * negative nquark_final means that it will not be possible to
1071  * find a constituent to change the flavor. */
1072  bool enough_quark = nquark_final >= 0;
1073  // If that is the case, excess of constituents will be modified
1074  if (!enough_quark) {
1075  logg[LPythia].debug(" not enough constituents with flavor ", iflav + 1,
1076  " : try to modify excess of constituents.");
1077  for (int ic = 0; ic < std::abs(nquark_final); ic++) {
1078  /* Since each incoming hadron has its own count of the excess,
1079  * it is necessary to find which one is problematic. */
1080  int ih_mod = -1;
1081  if (excess_quark[0][iflav] < 0) {
1082  ih_mod = 0;
1083  } else {
1084  ih_mod = 1;
1085  }
1086  /* Increase the excess of both quark and antiquark
1087  * with corresponding flavor (iflav + 1) by 1.
1088  * This is for conservation of the net quark number. */
1089  excess_quark[ih_mod][iflav] += 1;
1090  excess_antiq[ih_mod][iflav] += 1;
1091 
1092  /* Since incoming hadrons are mapped onto ones with
1093  * the same baryon number (or quark number),
1094  * summation of the excesses over all flavors should be zero.
1095  * Therefore, we need to find another flavor which has
1096  * a positive excess and subtract by 1. */
1097  for (int jflav = 0; jflav < 5; jflav++) {
1098  // another flavor with positive excess of constituents
1099  if (jflav != iflav && excess_quark[ih_mod][jflav] > 0) {
1100  /* Decrease the excess of both quark and antiquark
1101  * with corresponding flavor (jflav + 1) by 1. */
1102  excess_quark[ih_mod][jflav] -= 1;
1103  excess_antiq[ih_mod][jflav] -= 1;
1104  /* We only need to find one (another) flavor to subtract.
1105  * No more! */
1106  break;
1107  }
1108  }
1109  }
1110  }
1111  }
1112 }

◆ 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 1114 of file stringprocess.cc.

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

◆ 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 1273 of file stringprocess.cc.

1275  {
1276  Pythia8::Vec4 pSum = 0.;
1277  event_hadronize.reset();
1278 
1279  // select the most forward or backward parton.
1280  int iforward = get_index_forward(find_forward_string, 0, event_intermediate);
1281  logg[LPythia].debug("Hard non-diff: iforward = ", iforward, "(",
1282  event_intermediate[iforward].id(), ")");
1283 
1284  pSum += event_intermediate[iforward].p();
1285  event_hadronize.append(event_intermediate[iforward]);
1286 
1287  int col_to_find = event_intermediate[iforward].acol();
1288  int acol_to_find = event_intermediate[iforward].col();
1289  event_intermediate.remove(iforward, iforward);
1290  logg[LPythia].debug("Hard non-diff: event_intermediate reduces in size to ",
1291  event_intermediate.size());
1292 
1293  // trace color and anti-color indices and find corresponding partons.
1294  while (col_to_find != 0 || acol_to_find != 0) {
1295  logg[LPythia].debug(" col_to_find = ", col_to_find,
1296  ", acol_to_find = ", acol_to_find);
1297 
1298  int ifound = -1;
1299  for (int i = 1; i < event_intermediate.size(); i++) {
1300  const int pdgid = event_intermediate[i].id();
1301  bool found_col =
1302  col_to_find != 0 && col_to_find == event_intermediate[i].col();
1303  bool found_acol =
1304  acol_to_find != 0 && acol_to_find == event_intermediate[i].acol();
1305  if (found_col) {
1306  logg[LPythia].debug(" col_to_find ", col_to_find, " from i ", i, "(",
1307  pdgid, ") found");
1308  }
1309  if (found_acol) {
1310  logg[LPythia].debug(" acol_to_find ", acol_to_find, " from i ", i, "(",
1311  pdgid, ") found");
1312  }
1313 
1314  if (found_col && !found_acol) {
1315  ifound = i;
1316  col_to_find = event_intermediate[i].acol();
1317  break;
1318  } else if (!found_col && found_acol) {
1319  ifound = i;
1320  acol_to_find = event_intermediate[i].col();
1321  break;
1322  } else if (found_col && found_acol) {
1323  ifound = i;
1324  col_to_find = 0;
1325  acol_to_find = 0;
1326  break;
1327  }
1328  }
1329 
1330  if (ifound < 0) {
1331  event_intermediate.list();
1332  event_intermediate.listJunctions();
1333  event_hadronize.list();
1334  event_hadronize.listJunctions();
1335  if (col_to_find != 0) {
1336  logg[LPythia].error("No parton with col = ", col_to_find);
1337  }
1338  if (acol_to_find != 0) {
1339  logg[LPythia].error("No parton with acol = ", acol_to_find);
1340  }
1341  throw std::runtime_error("Hard string could not be identified.");
1342  } else {
1343  pSum += event_intermediate[ifound].p();
1344  // add a parton to the new event record.
1345  event_hadronize.append(event_intermediate[ifound]);
1346  // then remove from the original event record.
1347  event_intermediate.remove(ifound, ifound);
1348  logg[LPythia].debug(
1349  "Hard non-diff: event_intermediate reduces in size to ",
1350  event_intermediate.size());
1351  }
1352  }
1353 
1354  /* The zeroth entry of event record is supposed to have the information
1355  * on the whole system. Specify the total momentum and invariant mass. */
1356  event_hadronize[0].p(pSum);
1357  event_hadronize[0].m(pSum.mCalc());
1358 }

◆ 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 1360 of file stringprocess.cc.

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

◆ 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 1463 of file stringprocess.cc.

1465  {
1466  Pythia8::Vec4 pSum = event_hadronize[0].p();
1467  for (unsigned int j = 0; j < col.size(); j++) {
1468  if (col[j] == 0) {
1469  continue;
1470  }
1471  bool found_leg = false;
1472  while (!found_leg) {
1473  int ifound = -1;
1474  for (int i = 1; i < event_intermediate.size(); i++) {
1475  const int pdgid = event_intermediate[i].id();
1476  if (sign_color && col[j] == event_intermediate[i].col()) {
1477  logg[LPythia].debug(" col[", j, "] = ", col[j], " from i ", i, "(",
1478  pdgid, ") found");
1479  ifound = i;
1480  col[j] = event_intermediate[i].acol();
1481  break;
1482  } else if (!sign_color && col[j] == event_intermediate[i].acol()) {
1483  logg[LPythia].debug(" acol[", j, "] = ", col[j], " from i ", i, "(",
1484  pdgid, ") found");
1485  ifound = i;
1486  col[j] = event_intermediate[i].col();
1487  break;
1488  }
1489  }
1490 
1491  if (ifound < 0) {
1492  found_leg = true;
1493  if (event_intermediate.sizeJunction() == 0) {
1494  event_intermediate.list();
1495  event_intermediate.listJunctions();
1496  event_hadronize.list();
1497  event_hadronize.listJunctions();
1498  logg[LPythia].error("No parton with col = ", col[j],
1499  " connected with junction leg ", j);
1500  throw std::runtime_error("Hard string could not be identified.");
1501  }
1502  } else {
1503  pSum += event_intermediate[ifound].p();
1504  // add a parton to the new event record.
1505  event_hadronize.append(event_intermediate[ifound]);
1506  // then remove from the original event record.
1507  event_intermediate.remove(ifound, ifound);
1508  logg[LPythia].debug(
1509  "Hard non-diff: event_intermediate reduces in size to ",
1510  event_intermediate.size());
1511  if (col[j] == 0) {
1512  found_leg = true;
1513  }
1514  }
1515  }
1516  }
1517 
1518  /* The zeroth entry of event record is supposed to have the information
1519  * on the whole system. Specify the total momentum and invariant mass. */
1520  event_hadronize[0].p(pSum);
1521  event_hadronize[0].m(pSum.mCalc());
1522 }

◆ 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 764 of file stringprocess.h.

765  {
766  int iforward = 1;
767  for (int ip = 2; ip < event.size() - np_end; ip++) {
768  const double y_quark_current = event[ip].y();
769  const double y_quark_forward = event[iforward].y();
770  if ((find_forward && y_quark_current > y_quark_forward) ||
771  (!find_forward && y_quark_current < y_quark_forward)) {
772  iforward = ip;
773  }
774  }
775  return iforward;
776  }

◆ 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 783 of file stringprocess.h.

783 { return final_state_; }

◆ clear_final_state()

void smash::StringProcess::clear_final_state ( )
inline

a function that clears the final state particle list which is used for testing mainly

Definition at line 789 of file stringprocess.h.

789 { final_state_.clear(); }

◆ 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 [3].

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 157 of file stringprocess.cc.

159  {
160  int nfrag = 0;
161  int bstring = 0;
162 
163  for (ParticleData &data : intermediate_particles) {
164  nfrag += 1;
165  bstring += data.pdgcode().baryon_number();
166  }
167  assert(nfrag > 0);
168 
169  /* compute the cross section scaling factor for leading hadrons
170  * based on the number of valence quarks. */
171  assign_all_scaling_factors(bstring, intermediate_particles, evecLong,
173 
174  // Velocity three-vector to perform Lorentz boost.
175  const ThreeVector vstring = uString.velocity();
176 
177  // compute the formation times of hadrons
178  for (int i = 0; i < nfrag; i++) {
179  ThreeVector velocity = intermediate_particles[i].momentum().velocity();
180  double gamma = 1. / intermediate_particles[i].inverse_gamma();
181  // boost 4-momentum into the center of mass frame
182  FourVector momentum =
183  intermediate_particles[i].momentum().lorentz_boost(-vstring);
184  intermediate_particles[i].set_4momentum(momentum);
185 
187  // set the formation time and position in the rest frame of string
188  double tau_prod = M_SQRT2 * intermediate_particles[i].effective_mass() /
190  double t_prod = tau_prod * gamma;
191  FourVector fragment_position = FourVector(t_prod, t_prod * velocity);
192  /* boost formation position into the center of mass frame
193  * and then into the lab frame */
194  fragment_position = fragment_position.lorentz_boost(-vstring);
195  fragment_position = fragment_position.lorentz_boost(-vcomAB_);
196  intermediate_particles[i].set_slow_formation_times(
198  soft_t_form_ * fragment_position.x0() + time_collision_);
199  } else {
200  ThreeVector v_calc = momentum.lorentz_boost(-vcomAB_).velocity();
201  double gamma_factor = 1.0 / std::sqrt(1 - (v_calc).sqr());
202  intermediate_particles[i].set_slow_formation_times(
204  time_formation_const_ * gamma_factor + time_collision_);
205  }
206 
207  final_state_.push_back(intermediate_particles[i]);
208  }
209 
210  return nfrag;
211 }
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.

◆ 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 815 of file stringprocess.h.

816  {
817  const std::string s = std::to_string(pdgid);
818  PdgCode pythia_code(s);
819  ParticleTypePtr new_type = ParticleType::try_find(pythia_code);
820  if (new_type) {
821  ParticleData new_particle(ParticleType::find(pythia_code));
822  new_particle.set_4momentum(momentum);
823  intermediate_particles.push_back(new_particle);
824  return true;
825  } else {
826  // if the particle does not exist in SMASH the pythia event is rerun
827  return false;
828  }
829  }
static const ParticleTypePtr try_find(PdgCode pdgcode)
Returns the ParticleTypePtr for the given pdgcode.
Definition: particletype.cc:89

◆ 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 835 of file stringprocess.h.

835  {
836  if (pythia_id == 310 || pythia_id == 130) {
837  pythia_id = (random::uniform_int(0, 1) == 0) ? 311 : -311;
838  }
839  }

◆ 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 1692 of file stringprocess.cc.

1693  {
1694  // The 4-digit pdg id should be diquark.
1695  assert((std::abs(diquark) > 1000) && (std::abs(diquark) < 5510) &&
1696  (std::abs(diquark) % 100 < 10));
1697 
1698  // The fourth digit corresponds to the spin degeneracy.
1699  deg_spin = std::abs(diquark) % 10;
1700  // Diquark (anti-diquark) is decomposed into two quarks (antiquarks).
1701  const int sign_anti = diquark > 0 ? 1 : -1;
1702 
1703  // Obtain two quarks (or antiquarks) from the first and second digit.
1704  q1 = sign_anti * (std::abs(diquark) - (std::abs(diquark) % 1000)) / 1000;
1705  q2 = sign_anti * (std::abs(diquark) % 1000 - deg_spin) / 100;
1706 }

◆ 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 1708 of file stringprocess.cc.

1708  {
1709  assert((q1 > 0 && q2 > 0) || (q1 < 0 && q2 < 0));
1710  if (std::abs(q1) < std::abs(q2)) {
1711  std::swap(q1, q2);
1712  }
1713  int diquark = std::abs(q1 * 1000 + q2 * 100);
1714  /* Adding spin degeneracy = 2S+1. For identical quarks spin cannot be 0
1715  * because of Pauli exclusion principle, so spin 1 is assumed. Otherwise
1716  * S = 0 with probability 1/4 and S = 1 with probability 3/4. */
1717  diquark += (q1 != q2 && random::uniform_int(0, 3) == 0) ? 1 : 3;
1718  return (q1 < 0) ? -diquark : diquark;
1719 }

◆ 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 1721 of file stringprocess.cc.

1722  {
1723  std::array<int, 3> quarks = pdg.quark_content();
1724  if (pdg.is_nucleon()) {
1725  // protons and neutrons treated seperately since single quarks is at a
1726  // different position in the PDG code
1727  if (pdg.charge() == 0) { // (anti)neutron
1728  if (random::uniform(0., 1.) < xi) {
1729  idq1 = quarks[0];
1730  idq2 = diquark_from_quarks(quarks[1], quarks[2]);
1731  } else {
1732  idq1 = quarks[1];
1733  idq2 = diquark_from_quarks(quarks[0], quarks[2]);
1734  }
1735  } else { // (anti)proton
1736  if (random::uniform(0., 1.) < xi) {
1737  idq1 = quarks[2];
1738  idq2 = diquark_from_quarks(quarks[0], quarks[1]);
1739  } else {
1740  idq1 = quarks[0];
1741  idq2 = diquark_from_quarks(quarks[1], quarks[2]);
1742  }
1743  }
1744  } else {
1745  if (pdg.is_meson()) {
1746  idq1 = quarks[1];
1747  idq2 = quarks[2];
1748  /* Some mesons with PDG id 11X are actually mixed state of uubar and
1749  * ddbar. have a random selection whether we have uubar or ddbar in this
1750  * case. */
1751  if (idq1 == 1 && idq2 == -1 && random::uniform_int(0, 1) == 0) {
1752  idq1 = 2;
1753  idq2 = -2;
1754  }
1755  } else {
1756  assert(pdg.is_baryon());
1757  // Get random quark to position 0
1758  std::swap(quarks[random::uniform_int(0, 2)], quarks[0]);
1759  idq1 = quarks[0];
1760  idq2 = diquark_from_quarks(quarks[1], quarks[2]);
1761  }
1762  }
1763  // Fulfil the convention: idq1 should be quark or anti-diquark
1764  if (idq1 < 0) {
1765  std::swap(idq1, idq2);
1766  }
1767 }
static int diquark_from_quarks(int q1, int q2)
Construct diquark from two quarks.
T uniform(T min, T max)
Definition: random.h:88

◆ 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 875 of file stringprocess.h.

875  {
876  return Pythia8::Vec4(mom.x1(), mom.x2(), mom.x3(), energy);
877  }

◆ 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 890 of file stringprocess.h.

891  {
892  ThreeVector three_momentum = evec_basis[0] * particle.pz() +
893  evec_basis[1] * particle.px() +
894  evec_basis[2] * particle.py();
895  return FourVector(particle.e(), three_momentum);
896  }

◆ 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 exploiting PYTHIA 8.3 Andersson:1983ia [3], Sjostrand:2014zea [52], Bierlich:2022pfr [8].

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 1769 of file stringprocess.cc.

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

◆ 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 2241 of file stringprocess.cc.

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

◆ 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 2572 of file stringprocess.cc.

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

◆ 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 2660 of file stringprocess.cc.

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

◆ 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 2786 of file stringprocess.cc.

2790  {
2791  const double mTsqr_string = 2. * ppos_string * pneg_string;
2792  if (mTsqr_string < 0.) {
2793  return false;
2794  }
2795  const double mTrn_string = std::sqrt(mTsqr_string);
2796  if (mTrn_string < mTrn_had_forward + mTrn_had_backward) {
2797  return false;
2798  }
2799 
2800  // square of transvere mass of the forward hadron
2801  const double mTsqr_had_forward = mTrn_had_forward * mTrn_had_forward;
2802  // square of transvere mass of the backward hadron
2803  const double mTsqr_had_backward = mTrn_had_backward * mTrn_had_backward;
2804 
2805  /* The following part determines lightcone momentum fraction of p^+
2806  * carried by each hadron.
2807  * Lightcone momenta of the forward and backward hadrons are
2808  * p^+ forward = (xe_pos + xpz_pos) * p^+ string,
2809  * p^- forward = (xe_pos - xpz_pos) * p^- string,
2810  * p^+ backward = (xe_neg - xpz_pos) * p^+ string and
2811  * p^- backward = (xe_neg + xpz_pos) * p^- string.
2812  * where xe_pos and xe_neg satisfy xe_pos + xe_neg = 1.
2813  * Then evaluate xe_pos, xe_neg and xpz_pos in terms of
2814  * the transverse masses of hadrons and string. */
2815 
2816  // Express xe_pos and xe_neg in terms of the transverse masses.
2817  const double xm_diff =
2818  (mTsqr_had_forward - mTsqr_had_backward) / mTsqr_string;
2819  const double xe_pos = 0.5 * (1. + xm_diff);
2820  const double xe_neg = 0.5 * (1. - xm_diff);
2821 
2822  // Express xpz_pos in terms of the transverse masses.
2823  const double lambda_sqr =
2824  pow_int(mTsqr_string - mTsqr_had_forward - mTsqr_had_backward, 2) -
2825  4. * mTsqr_had_forward * mTsqr_had_backward;
2826  if (lambda_sqr <= 0.) {
2827  return false;
2828  }
2829  const double lambda = std::sqrt(lambda_sqr);
2830  const double b_lund =
2831  separate_fragment_hadron ? stringz_b_leading_ : stringz_b_produce_;
2832  /* The probability to flip sign of xpz_pos is taken from
2833  * StringFragmentation::finalTwo in StringFragmentation.cc
2834  * of PYTHIA 8. */
2835  const double prob_reverse =
2836  std::exp(-b_lund * lambda) / (1. + std::exp(-b_lund * lambda));
2837  double xpz_pos = 0.5 * lambda / mTsqr_string;
2838  if (random::uniform(0., 1.) < prob_reverse) {
2839  xpz_pos = -xpz_pos;
2840  }
2841 
2842  ppos_had_forward = (xe_pos + xpz_pos) * ppos_string;
2843  ppos_had_backward = (xe_neg - xpz_pos) * ppos_string;
2844 
2845  pneg_had_forward = 0.5 * mTsqr_had_forward / ppos_had_forward;
2846  pneg_had_backward = 0.5 * mTsqr_had_backward / ppos_had_backward;
2847 
2848  return true;
2849 }
constexpr T pow_int(const T base, unsigned const exponent)
Efficient template for calculating integer powers using squaring.
Definition: pow.h:23

◆ 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 2851 of file stringprocess.cc.

2851  {
2852  // the lightcone momentum fraction x
2853  double xfrac = 0.;
2854  bool xfrac_accepted = false;
2855  /* First sample the inverse 1/x of the lightcone momentum fraction.
2856  * Then, obtain x itself.
2857  * The probability distribution function for the inverse of x is
2858  * PDF(u = 1/x) = (1/u) * (1 - 1/u)^a * exp(-b * mTrn^2 * u)
2859  * with 1 < u < infinity.
2860  * The rejection method can be used with an envelop function
2861  * ENV(u) = exp(-b * mTrn^2 * u). */
2862  while (!xfrac_accepted) {
2863  const double fac_env = b * mTrn * mTrn;
2864  const double u_aux = random::uniform(0., 1.);
2865  /* Sample u = 1/x according to the envelop function
2866  * ENV(u) = exp(-b * mTrn^2 * u). */
2867  const double xfrac_inv = 1. - std::log(u_aux) / fac_env;
2868  assert(xfrac_inv >= 1.);
2869  /* Evaluate the ratio of the real probability distribution function to
2870  * the envelop function. */
2871  const double xf_ratio = std::pow(1. - 1. / xfrac_inv, a) / xfrac_inv;
2872  // Determine whether the sampled value will be accepted.
2873  if (random::uniform(0., 1.) <= xf_ratio) {
2874  /* If the sampled value of 1/x is accepted,
2875  * obtain the value of x. */
2876  xfrac = 1. / xfrac_inv;
2877  xfrac_accepted = true;
2878  }
2879  }
2880  return xfrac;
2881 }

◆ 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 2883 of file stringprocess.cc.

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

◆ 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 1060 of file stringprocess.h.

1062  {
1063  Pythia8::Vec4 pvec_string_now = Pythia8::Vec4(0., 0., 0., 0.);
1064  // loop over all particles in the record
1065  for (int ipyth = 1; ipyth < event.size(); ipyth++) {
1066  if (!event[ipyth].isFinal()) {
1067  continue;
1068  }
1069 
1070  FourVector p_frag = FourVector(
1071  event[ipyth].e(), event[ipyth].px(),
1072  event[ipyth].py(), event[ipyth].pz());
1073  const double E_frag = p_frag.x0();
1074  const double pl_frag = p_frag.threevec() * evec_basis[0];
1075  const double ppos_frag = (E_frag + pl_frag) * M_SQRT1_2;
1076  const double pneg_frag = (E_frag - pl_frag) * M_SQRT1_2;
1077  const double mTrn_frag = std::sqrt(2. * ppos_frag * pneg_frag);
1078  // evaluate the old momentum rapidity
1079  const double y_frag = 0.5 * std::log(ppos_frag / pneg_frag);
1080 
1081  // obtain the new momentum rapidity
1082  const double y_new_frag = factor_yrapid * y_frag + diff_yrapid;
1083  // compute the new four momentum
1084  const double E_new_frag = mTrn_frag * std::cosh(y_new_frag);
1085  const double pl_new_frag = mTrn_frag * std::sinh(y_new_frag);
1086  ThreeVector mom_new_frag =
1087  p_frag.threevec() + (pl_new_frag - pl_frag) * evec_basis[0];
1088  Pythia8::Vec4 pvec_new_frag = set_Vec4(E_new_frag, mom_new_frag);
1089  event[ipyth].p(pvec_new_frag);
1090  pvec_string_now += pvec_new_frag;
1091  }
1092  event[0].p(pvec_string_now);
1093  event[0].m(pvec_string_now.mCalc());
1094  }

◆ 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 3212 of file stringprocess.cc.

3215  {
3216  // Set each particle's cross section scaling factor to 0 first
3217  for (ParticleData &data : outgoing_particles) {
3218  data.set_cross_section_scaling_factor(0.0);
3219  }
3220  // sort outgoing particles according to the longitudinal velocity
3221  std::sort(outgoing_particles.begin(), outgoing_particles.end(),
3222  [&](ParticleData i, ParticleData j) {
3223  return i.momentum().velocity() * evecLong >
3224  j.momentum().velocity() * evecLong;
3225  });
3226  int nq1, nq2; // number of quarks at both ends of the string
3227  switch (baryon_string) {
3228  case 0:
3229  nq1 = -1;
3230  nq2 = 1;
3231  break;
3232  case 1:
3233  nq1 = 2;
3234  nq2 = 1;
3235  break;
3236  case -1:
3237  nq1 = -2;
3238  nq2 = -1;
3239  break;
3240  default:
3241  throw std::runtime_error("string is neither mesonic nor baryonic");
3242  }
3243  // Try to find nq1 on one string end and nq2 on the other string end and the
3244  // other way around. When the leading particles are close to the string ends,
3245  // the quarks are assumed to be distributed this way.
3246  std::pair<int, int> i = find_leading(nq1, nq2, outgoing_particles);
3247  std::pair<int, int> j = find_leading(nq2, nq1, outgoing_particles);
3248  if (baryon_string == 0 && i.second - i.first < j.second - j.first) {
3249  assign_scaling_factor(nq2, outgoing_particles[j.first], suppression_factor);
3250  assign_scaling_factor(nq1, outgoing_particles[j.second],
3251  suppression_factor);
3252  } else {
3253  assign_scaling_factor(nq1, outgoing_particles[i.first], suppression_factor);
3254  assign_scaling_factor(nq2, outgoing_particles[i.second],
3255  suppression_factor);
3256  }
3257 }
static std::pair< int, int > find_leading(int nq1, int nq2, ParticleList &list)
Find the leading string fragments.
static void assign_scaling_factor(int nquark, ParticleData &data, double suppression_factor)
Assign a cross section scaling factor to the given particle.

◆ 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 3195 of file stringprocess.cc.

3196  {
3197  assert(list.size() >= 2);
3198  int end = list.size() - 1;
3199  int i1, i2;
3200  for (i1 = 0;
3201  i1 <= end && !list[i1].pdgcode().contains_enough_valence_quarks(nq1);
3202  i1++) {
3203  }
3204  for (i2 = end;
3205  i2 >= 0 && !list[i2].pdgcode().contains_enough_valence_quarks(nq2);
3206  i2--) {
3207  }
3208  std::pair<int, int> indices(i1, i2);
3209  return indices;
3210 }

◆ 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 3180 of file stringprocess.cc.

3181  {
3182  int nbaryon = data.pdgcode().baryon_number();
3183  if (nbaryon == 0) {
3184  // Mesons always get a scaling factor of 1/2 since there is never
3185  // a q-qbar pair at the end of a string so nquark is always 1
3186  data.set_cross_section_scaling_factor(0.5 * suppression_factor);
3187  } else if (data.is_baryon()) {
3188  // Leading baryons get a factor of 2/3 if they carry 2
3189  // and 1/3 if they carry 1 of the strings valence quarks
3190  data.set_cross_section_scaling_factor(suppression_factor * nquark /
3191  (3.0 * nbaryon));
3192  }
3193 }

◆ 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 3259 of file stringprocess.cc.

3259  {
3260  PdgCode pdg_mapped(0x0);
3261 
3262  if (pdg.baryon_number() == 1) { // baryon
3263  pdg_mapped = pdg.charge() > 0 ? PdgCode(pdg::p) : PdgCode(pdg::n);
3264  } else if (pdg.baryon_number() == -1) { // antibaryon
3265  pdg_mapped = pdg.charge() < 0 ? PdgCode(-pdg::p) : PdgCode(-pdg::n);
3266  } else if (pdg.is_hadron()) { // meson
3267  if (pdg.charge() >= 0) {
3268  pdg_mapped = PdgCode(pdg::pi_p);
3269  } else {
3270  pdg_mapped = PdgCode(pdg::pi_m);
3271  }
3272  } else if (pdg.is_lepton()) { // lepton
3273  pdg_mapped = pdg.charge() < 0 ? PdgCode(0x11) : PdgCode(-0x11);
3274  } else {
3275  throw std::runtime_error("StringProcess::pdg_map_for_pythia failed.");
3276  }
3277 
3278  return pdg_mapped.get_decimal();
3279 }
constexpr int pi_p
π⁺.
constexpr int p
Proton.
constexpr int n
Neutron.
constexpr int pi_m
π⁻.

◆ getPPosA()

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

Definition at line 1171 of file stringprocess.h.

1171 { 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 1177 of file stringprocess.h.

1177 { 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 1183 of file stringprocess.h.

1183 { 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 1189 of file stringprocess.h.

1189 { return PNegB_;}

◆ get_massA()

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

Definition at line 1195 of file stringprocess.h.

1195 { return massA_;}

◆ get_massB()

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

Definition at line 1201 of file stringprocess.h.

1201 { return massB_;}

◆ get_sqrts()

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

Definition at line 1207 of file stringprocess.h.

1207 { 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 1213 of file stringprocess.h.

1213 { 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 1219 of file stringprocess.h.

1219 { 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 1225 of file stringprocess.h.

1225 { 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 1231 of file stringprocess.h.

1231 { 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 1237 of file stringprocess.h.

1237 { return vcomAB_;}

◆ get_tcoll()

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

Definition at line 1243 of file stringprocess.h.

1243 { 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 49 of file stringprocess.h.

◆ PPosB_

double smash::StringProcess::PPosB_
private

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

Definition at line 51 of file stringprocess.h.

◆ PNegA_

double smash::StringProcess::PNegA_
private

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

Definition at line 53 of file stringprocess.h.

◆ PNegB_

double smash::StringProcess::PNegB_
private

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

Definition at line 55 of file stringprocess.h.

◆ massA_

double smash::StringProcess::massA_
private

mass of incoming particle A [GeV]

Definition at line 57 of file stringprocess.h.

◆ massB_

double smash::StringProcess::massB_
private

mass of incoming particle B [GeV]

Definition at line 59 of file stringprocess.h.

◆ sqrtsAB_

double smash::StringProcess::sqrtsAB_
private

sqrt of Mandelstam variable s of collision [GeV]

Definition at line 61 of file stringprocess.h.

◆ PDGcodes_

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

PdgCodes of incoming particles.

Definition at line 63 of file stringprocess.h.

◆ plab_

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

momenta of incoming particles in the lab frame [GeV]

Definition at line 65 of file stringprocess.h.

◆ pcom_

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

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

Definition at line 67 of file stringprocess.h.

◆ ucomAB_

FourVector smash::StringProcess::ucomAB_
private

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

Definition at line 69 of file stringprocess.h.

◆ vcomAB_

ThreeVector smash::StringProcess::vcomAB_
private

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

Definition at line 71 of file stringprocess.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 76 of file stringprocess.h.

◆ NpartFinal_

int smash::StringProcess::NpartFinal_
private

total number of final state particles

Definition at line 78 of file stringprocess.h.

◆ NpartString_

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

number of particles fragmented from strings

Definition at line 80 of file stringprocess.h.

◆ pmin_gluon_lightcone_

double smash::StringProcess::pmin_gluon_lightcone_
private

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

Definition at line 82 of file stringprocess.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 87 of file stringprocess.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 92 of file stringprocess.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 97 of file stringprocess.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 103 of file stringprocess.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 108 of file stringprocess.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 113 of file stringprocess.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 118 of file stringprocess.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 123 of file stringprocess.h.

◆ strange_supp_

double smash::StringProcess::strange_supp_
private

strange quark suppression factor

Definition at line 125 of file stringprocess.h.

◆ diquark_supp_

double smash::StringProcess::diquark_supp_
private

diquark suppression factor

Definition at line 127 of file stringprocess.h.

◆ popcorn_rate_

double smash::StringProcess::popcorn_rate_
private

popcorn rate

Definition at line 129 of file stringprocess.h.

◆ string_sigma_T_

double smash::StringProcess::string_sigma_T_
private

transverse momentum spread in string fragmentation

Definition at line 131 of file stringprocess.h.

◆ kappa_tension_string_

double smash::StringProcess::kappa_tension_string_
private

string tension [GeV/fm]

Definition at line 133 of file stringprocess.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 138 of file stringprocess.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 140 of file stringprocess.h.

◆ soft_t_form_

double smash::StringProcess::soft_t_form_
private

factor to be multiplied to formation times in soft strings

Definition at line 142 of file stringprocess.h.

◆ time_collision_

double smash::StringProcess::time_collision_
private

time of collision in the computational frame [fm]

Definition at line 144 of file stringprocess.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 [3] 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 156 of file stringprocess.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 161 of file stringprocess.h.

◆ separate_fragment_baryon_

bool smash::StringProcess::separate_fragment_baryon_
private

Whether to use a separate fragmentation function for leading baryons.

Definition at line 164 of file stringprocess.h.

◆ use_monash_tune_

bool smash::StringProcess::use_monash_tune_
private

Whether to use the monash tune Skands:2014pea [53] for all string processes.

Definition at line 170 of file stringprocess.h.

◆ final_state_

ParticleList smash::StringProcess::final_state_
private

final state array which must be accessed after the collision

Definition at line 176 of file stringprocess.h.

◆ hard_map_

pythia_map smash::StringProcess::hard_map_
private

Map object to contain the different pythia objects.

Definition at line 187 of file stringprocess.h.

◆ pythia_hadron_

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

PYTHIA object used in fragmentation.

Definition at line 190 of file stringprocess.h.

◆ pythia_sigmatot_

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

An object to compute cross-sections.

Definition at line 193 of file stringprocess.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 199 of file stringprocess.h.

◆ event_intermediate_

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

event record for intermediate partonic state in the hard string routine

Definition at line 205 of file stringprocess.h.


The documentation for this class was generated from the following files: