Version: SMASH-3.3
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 [6], Bleicher:1999xi [11] and subsequent fragmentation according to the LUND/PYTHIA fragmentation scheme Andersson:1983ia [4], Sjostrand:2014zea [57], Bierlich:2022pfr [9].

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 [54]. 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 [30]. 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 [6], Bleicher:1999xi [11]. More...
 
bool next_NDiffSoft ()
 Soft Non-diffractive process is modelled in accordance with dual-topological approach Capella:1978ig [16]. 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 [6], Bleicher:1999xi [11] 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 [4]. 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 [4], Sjostrand:2014zea [57], Bierlich:2022pfr [9]. 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 [4] 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 [58] 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 = 100000");
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
std::string to_string(ThermodynamicQuantity quantity)
Convert a ThermodynamicQuantity enum value to its corresponding string.
Definition: stringify.cc:26
constexpr double kaon_mass
Kaon mass in GeV.
Definition: constants.h:76

◆ 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:40
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:107
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 [54].

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

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

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

1687  {
1688  PPosA_ = (pcom_[0].x0() + evecBasisAB_[0] * pcom_[0].threevec()) * M_SQRT1_2;
1689  PNegA_ = (pcom_[0].x0() - evecBasisAB_[0] * pcom_[0].threevec()) * M_SQRT1_2;
1690  PPosB_ = (pcom_[1].x0() + evecBasisAB_[0] * pcom_[1].threevec()) * M_SQRT1_2;
1691  PNegB_ = (pcom_[1].x0() - evecBasisAB_[0] * pcom_[1].threevec()) * M_SQRT1_2;
1692 }
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 325 of file stringprocess.cc.

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

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

367  {
368  const std::array<FourVector, 2> ustr_com = {pstr_com[0] / m_str[0],
369  pstr_com[1] / m_str[1]};
370  for (int i = 0; i < 2; i++) {
371  ParticleList new_intermediate_particles;
372 
373  // determine direction in which string i is stretched.
374  ThreeVector evec = evec_str[i];
375  // perform fragmentation and add particles to final_state.
376  int nfrag = fragment_string(quarks[i][0], quarks[i][1], m_str[i], evec,
377  flip_string_ends, separate_fragment_baryon,
378  new_intermediate_particles);
379  if (nfrag <= 0) {
380  NpartString_[i] = 0;
381  return false;
382  }
383 
384  NpartString_[i] =
385  append_final_state(new_intermediate_particles, ustr_com[i], evec);
386  assert(nfrag == NpartString_[i]);
387  }
388  if ((NpartString_[0] > 0) && (NpartString_[1] > 0)) {
390  return true;
391  }
392  return false;
393 }
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 [30].

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 
310  NpartString_[0] =
311  append_final_state(new_intermediate_particles, ustrXcom, evec);
312 
313  NpartString_[1] = 1;
314  PdgCode hadron_code = is_AB_to_AX ? PDGcodes_[0] : PDGcodes_[1];
315  ParticleData new_particle(ParticleType::find(hadron_code));
316  new_particle.set_4momentum(pstrHcom);
317  new_particle.set_cross_section_scaling_factor(1.);
318  new_particle.set_formation_time(time_collision_);
319  final_state_.push_back(new_particle);
320 
322  return true;
323 }
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 [6], Bleicher:1999xi [11].

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

Returns
whether the process is successfully implemented.

Definition at line 396 of file stringprocess.cc.

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

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

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

Definition at line 451 of file stringprocess.cc.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

3261  {
3262  PdgCode pdg_mapped(0x0);
3263 
3264  if (pdg.baryon_number() == 1) { // baryon
3265  pdg_mapped = pdg.charge() > 0 ? PdgCode(pdg::p) : PdgCode(pdg::n);
3266  } else if (pdg.baryon_number() == -1) { // antibaryon
3267  pdg_mapped = pdg.charge() < 0 ? PdgCode(-pdg::p) : PdgCode(-pdg::n);
3268  } else if (pdg.is_hadron()) { // meson
3269  if (pdg.charge() >= 0) {
3270  pdg_mapped = PdgCode(pdg::pi_p);
3271  } else {
3272  pdg_mapped = PdgCode(pdg::pi_m);
3273  }
3274  } else if (pdg.is_lepton()) { // lepton
3275  pdg_mapped = pdg.charge() < 0 ? PdgCode(0x11) : PdgCode(-0x11);
3276  } else {
3277  throw std::runtime_error("StringProcess::pdg_map_for_pythia failed.");
3278  }
3279 
3280  return pdg_mapped.get_decimal();
3281 }
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 [4] 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 [58] 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: