Version: SMASH-2.0
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 [4], Bleicher:1999xi [8] and subsequent fragmentation according to the LUND/PYTHIA fragmentation scheme Andersson:1983ia [2], Sjostrand:2014zea [46].

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.

Collaboration diagram for smash::StringProcess:
[legend]

Public Member Functions

 StringProcess (double string_tension, double time_formation, double gluon_beta, double gluon_pmin, double quark_alpha, double quark_beta, double strange_supp, double diquark_supp, double sigma_perp, double stringz_a_leading, double stringz_b_leading, double stringz_a, double stringz_b, double string_sigma_T, double factor_t_form, bool mass_dependent_formation_times, double prob_proton_to_d_uu, bool separate_fragment_baryon, double popcorn_rate)
 Constructor, initializes pythia. More...
 
void common_setup_pythia (Pythia8::Pythia *pythia_in, double strange_supp, double diquark_supp, double popcorn_rate, double stringz_a, double stringz_b, double string_sigma_T)
 Common setup of PYTHIA objects for soft and hard string routines. More...
 
void init_pythia_hadron_rndm ()
 Set PYTHIA random seeds to be desired values. More...
 
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 [43]. 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 [24]. More...
 
bool next_DDiff ()
 Double-diffractive process ( A + B -> X + X ) is similar to the single-diffractive process, but lightcone momenta of gluons are sampled in the same was as the UrQMD model Bass:1998ca [4], Bleicher:1999xi [8]. More...
 
bool next_NDiffSoft ()
 Soft Non-diffractive process is modelled in accordance with dual-topological approach Capella:1978ig [12]. More...
 
bool next_NDiffHard ()
 Hard Non-diffractive process is based on PYTHIA 8 with partonic showers and interactions. More...
 
bool next_BBbarAnn ()
 Baryon-antibaryon annihilation process Based on what UrQMD Bass:1998ca [4], Bleicher:1999xi [8] does, it create two mesonic strings after annihilating one quark-antiquark pair. More...
 
void replace_constituent (Pythia8::Particle &particle, std::array< int, 5 > &excess_constituent)
 Convert a partonic PYTHIA particle into the desired species and update the excess of constituents. More...
 
void find_total_number_constituent (Pythia8::Event &event_intermediate, std::array< int, 5 > &nquark_total, std::array< int, 5 > &nantiq_total)
 Compute how many quarks and antiquarks we have in the system, and update the correspoing arrays with size 5. More...
 
bool splitting_gluon_qqbar (Pythia8::Event &event_intermediate, std::array< int, 5 > &nquark_total, std::array< int, 5 > &nantiq_total, bool sign_constituent, std::array< std::array< int, 5 >, 2 > &excess_constituent)
 Take total number of quarks and check if the system has enough constituents that need to be converted into other flavors. More...
 
void rearrange_excess (std::array< int, 5 > &nquark_total, std::array< std::array< int, 5 >, 2 > &excess_quark, std::array< std::array< int, 5 >, 2 > &excess_antiq)
 Take total number of quarks and check if the system has enough constituents that need to be converted into other flavors. More...
 
bool restore_constituent (Pythia8::Event &event_intermediate, std::array< std::array< int, 5 >, 2 > &excess_quark, std::array< std::array< int, 5 >, 2 > &excess_antiq)
 Take the intermediate partonic state from PYTHIA event with mapped hadrons and convert constituents into the desired ones according to the excess of quarks and anti-quarks. More...
 
void compose_string_parton (bool find_forward_string, Pythia8::Event &event_intermediate, Pythia8::Event &event_hadronize)
 Identify a set of partons, which are connected to form a color-neutral string, from a given PYTHIA event record. More...
 
void compose_string_junction (bool &find_forward_string, Pythia8::Event &event_intermediate, Pythia8::Event &event_hadronize)
 Identify a set of partons and junction(s), which are connected to form a color-neutral string, from a given PYTHIA event record. More...
 
void find_junction_leg (bool sign_color, std::vector< int > &col, Pythia8::Event &event_intermediate, Pythia8::Event &event_hadronize)
 Identify partons, which are associated with junction legs, from a given PYTHIA event record. More...
 
int get_index_forward (bool find_forward, int np_end, Pythia8::Event &event)
 Obtain index of the most forward or backward particle in a given PYTHIA event record. More...
 
ParticleList get_final_state ()
 a function to get the final state particle list which is called after the collision More...
 
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 [2]. More...
 
int fragment_string (int idq1, int idq2, double mString, ThreeVector &evecLong, bool flip_string_ends, bool separate_fragment_baryon, ParticleList &intermediate_particles)
 perform string fragmentation to determine species and momenta of hadrons by implementing PYTHIA 8.2 Andersson:1983ia [2], Sjostrand:2014zea [46]. 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 [2] eq. More...
 
double prob_proton_to_d_uu_
 Probability of splitting a nucleon into the quark flavour it has only once and a diquark it has twice. More...
 
bool separate_fragment_baryon_
 Whether to use a separate fragmentation function for leading baryons. More...
 
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 178 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 
)

Constructor, initializes pythia.

Should only be called once.

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

29  : pmin_gluon_lightcone_(gluon_pmin),
30  pow_fgluon_beta_(gluon_beta),
31  pow_fquark_alpha_(quark_alpha),
32  pow_fquark_beta_(quark_beta),
33  sigma_qperp_(sigma_perp),
34  stringz_a_leading_(stringz_a_leading),
35  stringz_b_leading_(stringz_b_leading),
36  stringz_a_produce_(stringz_a),
37  stringz_b_produce_(stringz_b),
38  strange_supp_(strange_supp),
39  diquark_supp_(diquark_supp),
40  popcorn_rate_(popcorn_rate),
41  string_sigma_T_(string_sigma_T),
42  kappa_tension_string_(string_tension),
44  time_formation_const_(time_formation),
45  soft_t_form_(factor_t_form),
46  time_collision_(0.),
47  mass_dependent_formation_times_(mass_dependent_formation_times),
48  prob_proton_to_d_uu_(prob_proton_to_d_uu),
49  separate_fragment_baryon_(separate_fragment_baryon) {
50  // setup and initialize pythia for fragmentation
51  pythia_hadron_ = make_unique<Pythia8::Pythia>(PYTHIA_XML_DIR, false);
52  /* turn off all parton-level processes to implement only hadronization */
53  pythia_hadron_->readString("ProcessLevel:all = off");
54  common_setup_pythia(pythia_hadron_.get(), strange_supp, diquark_supp,
55  popcorn_rate, stringz_a, stringz_b, string_sigma_T);
56 
57  /* initialize PYTHIA */
58  pythia_hadron_->init();
59 
60  /*
61  * The const_cast<type>() function is used to obtain the reference of the
62  * PrivateInfo object in the pythia_hadron_.
63  * This cast is needed since Pythia 8.302 which included a major architecture
64  * change. The Info object of a Pythia object is now private, only a const
65  * reference can be obtained.
66  * In order to reference the PrivateInfo object during initialization, we
67  * cast the const reference to obtain the stored address.
68  */
69  pythia_sigmatot_.initInfoPtr(
70  const_cast<Pythia8::Info &>(pythia_hadron_->info));
71  pythia_sigmatot_.init();
72 
73  pythia_stringflav_.initInfoPtr(
74  const_cast<Pythia8::Info &>(pythia_hadron_->info));
75  pythia_stringflav_.init();
76 
77  event_intermediate_.init("intermediate partons",
78  &pythia_hadron_->particleData);
79 
80  for (int imu = 0; imu < 3; imu++) {
81  evecBasisAB_[imu] = ThreeVector(0., 0., 0.);
82  }
83 
84  final_state_.clear();
85 }
Here is the call graph for this function:

Member Function Documentation

◆ common_setup_pythia()

void smash::StringProcess::common_setup_pythia ( Pythia8::Pythia *  pythia_in,
double  strange_supp,
double  diquark_supp,
double  popcorn_rate,
double  stringz_a,
double  stringz_b,
double  string_sigma_T 
)

Common setup of PYTHIA objects for soft and hard string routines.

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

Definition at line 87 of file stringprocess.cc.

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

◆ init_pythia_hadron_rndm()

void smash::StringProcess::init_pythia_hadron_rndm ( )
inline

Set PYTHIA random seeds to be desired values.

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

See also
smash::maximum_rndm_seed_in_pythia

Definition at line 289 of file stringprocess.h.

289  {
290  const int seed_new =
292 
293  pythia_hadron_->rndm.init(seed_new);
294  logg[LPythia].debug("pythia_hadron_ : rndm is initialized with seed ",
295  seed_new);
296  }
Here is the call graph for this function:

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

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

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

◆ set_pmin_gluon_lightcone()

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

set the minimum lightcone momentum scale carried by gluon.

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

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

Parameters
p_light_cone_mina value that we want to use for pmin_gluon_lightcone_.

Definition at line 345 of file stringprocess.h.

345  {
346  pmin_gluon_lightcone_ = p_light_cone_min;
347  }

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

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

364  {
365  pow_fquark_alpha_ = alphapow;
366  pow_fquark_beta_ = betapow;
367  }

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

372 { 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 377 of file stringprocess.h.

377  {
378  kappa_tension_string_ = kappa_string;
379  }

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

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

◆ make_orthonormal_basis()

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

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

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

Definition at line 1630 of file stringprocess.cc.

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

◆ compute_incoming_lightcone_momenta()

void smash::StringProcess::compute_incoming_lightcone_momenta ( )

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

Definition at line 1679 of file stringprocess.cc.

1679  {
1680  PPosA_ = (pcom_[0].x0() + evecBasisAB_[0] * pcom_[0].threevec()) * M_SQRT1_2;
1681  PNegA_ = (pcom_[0].x0() - evecBasisAB_[0] * pcom_[0].threevec()) * M_SQRT1_2;
1682  PPosB_ = (pcom_[1].x0() + evecBasisAB_[0] * pcom_[1].threevec()) * M_SQRT1_2;
1683  PNegB_ = (pcom_[1].x0() - evecBasisAB_[0] * pcom_[1].threevec()) * M_SQRT1_2;
1684 }
Here is the caller graph for this function:

◆ set_mass_and_direction_2strings()

bool smash::StringProcess::set_mass_and_direction_2strings ( const std::array< std::array< int, 2 >, 2 > &  quarks,
const std::array< FourVector, 2 > &  pstr_com,
std::array< double, 2 > &  m_str,
std::array< ThreeVector, 2 > &  evec_str 
)

Determine string masses and directions in which strings are stretched.

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

Definition at line 318 of file stringprocess.cc.

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

◆ make_final_state_2strings()

bool smash::StringProcess::make_final_state_2strings ( const std::array< std::array< int, 2 >, 2 > &  quarks,
const std::array< FourVector, 2 > &  pstr_com,
const std::array< double, 2 > &  m_str,
const std::array< ThreeVector, 2 > &  evec_str,
bool  flip_string_ends,
bool  separate_fragment_baryon 
)

Prepare kinematics of two strings, fragment them and append to final_state.

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

Definition at line 355 of file stringprocess.cc.

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

◆ next_SDiff()

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

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

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

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

◆ next_DDiff()

bool smash::StringProcess::next_DDiff ( )

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

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

Returns
whether the process is successfully implemented.

Definition at line 388 of file stringprocess.cc.

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

◆ next_NDiffSoft()

bool smash::StringProcess::next_NDiffSoft ( )

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

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

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

Definition at line 443 of file stringprocess.cc.

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

◆ next_NDiffHard()

bool smash::StringProcess::next_NDiffHard ( )

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

Returns
whether the process is successfully implemented.

Definition at line 520 of file stringprocess.cc.

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

◆ next_BBbarAnn()

bool smash::StringProcess::next_BBbarAnn ( )

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

Each string has mass equal to half of sqrts.

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

Definition at line 1519 of file stringprocess.cc.

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

◆ find_excess_constituent()

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

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

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

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

Definition at line 770 of file stringprocess.cc.

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

◆ replace_constituent()

void smash::StringProcess::replace_constituent ( Pythia8::Particle &  particle,
std::array< int, 5 > &  excess_constituent 
)

Convert a partonic PYTHIA particle into the desired species and update the excess of constituents.

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

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

Definition at line 804 of file stringprocess.cc.

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

◆ find_total_number_constituent()

void smash::StringProcess::find_total_number_constituent ( Pythia8::Event &  event_intermediate,
std::array< int, 5 > &  nquark_total,
std::array< int, 5 > &  nantiq_total 
)

Compute how many quarks and antiquarks we have in the system, and update the correspoing arrays with size 5.

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

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

Definition at line 889 of file stringprocess.cc.

891  {
892  for (int iflav = 0; iflav < 5; iflav++) {
893  nquark_total[iflav] = 0;
894  nantiq_total[iflav] = 0;
895  }
896 
897  for (int ip = 1; ip < event_intermediate.size(); ip++) {
898  if (!event_intermediate[ip].isFinal()) {
899  continue;
900  }
901  const int pdgid = event_intermediate[ip].id();
902  if (pdgid > 0) {
903  // quarks
904  for (int iflav = 0; iflav < 5; iflav++) {
905  nquark_total[iflav] +=
906  pythia_hadron_->particleData.nQuarksInCode(pdgid, iflav + 1);
907  }
908  } else {
909  // antiquarks
910  for (int iflav = 0; iflav < 5; iflav++) {
911  nantiq_total[iflav] += pythia_hadron_->particleData.nQuarksInCode(
912  std::abs(pdgid), iflav + 1);
913  }
914  }
915  }
916 }
Here is the caller graph for this function:

◆ splitting_gluon_qqbar()

bool smash::StringProcess::splitting_gluon_qqbar ( Pythia8::Event &  event_intermediate,
std::array< int, 5 > &  nquark_total,
std::array< int, 5 > &  nantiq_total,
bool  sign_constituent,
std::array< std::array< int, 5 >, 2 > &  excess_constituent 
)

Take total number of quarks and check if the system has enough constituents that need to be converted into other flavors.

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

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

Definition at line 918 of file stringprocess.cc.

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

◆ rearrange_excess()

void smash::StringProcess::rearrange_excess ( std::array< int, 5 > &  nquark_total,
std::array< std::array< int, 5 >, 2 > &  excess_quark,
std::array< std::array< int, 5 >, 2 > &  excess_antiq 
)

Take total number of quarks and check if the system has enough constituents that need to be converted into other flavors.

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

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

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

Definition at line 1051 of file stringprocess.cc.

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

◆ restore_constituent()

bool smash::StringProcess::restore_constituent ( Pythia8::Event &  event_intermediate,
std::array< std::array< int, 5 >, 2 > &  excess_quark,
std::array< std::array< int, 5 >, 2 > &  excess_antiq 
)

Take the intermediate partonic state from PYTHIA event with mapped hadrons and convert constituents into the desired ones according to the excess of quarks and anti-quarks.

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

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

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

Definition at line 1108 of file stringprocess.cc.

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

◆ compose_string_parton()

void smash::StringProcess::compose_string_parton ( bool  find_forward_string,
Pythia8::Event &  event_intermediate,
Pythia8::Event &  event_hadronize 
)

Identify a set of partons, which are connected to form a color-neutral string, from a given PYTHIA event record.

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

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

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

Definition at line 1267 of file stringprocess.cc.

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

◆ compose_string_junction()

void smash::StringProcess::compose_string_junction ( bool &  find_forward_string,
Pythia8::Event &  event_intermediate,
Pythia8::Event &  event_hadronize 
)

Identify a set of partons and junction(s), which are connected to form a color-neutral string, from a given PYTHIA event record.

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

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

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

Definition at line 1354 of file stringprocess.cc.

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

◆ find_junction_leg()

void smash::StringProcess::find_junction_leg ( bool  sign_color,
std::vector< int > &  col,
Pythia8::Event &  event_intermediate,
Pythia8::Event &  event_hadronize 
)

Identify partons, which are associated with junction legs, from a given PYTHIA event record.

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

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

Definition at line 1457 of file stringprocess.cc.

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

◆ get_index_forward()

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

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

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

Definition at line 754 of file stringprocess.h.

755  {
756  int iforward = 1;
757  for (int ip = 2; ip < event.size() - np_end; ip++) {
758  const double y_quark_current = event[ip].y();
759  const double y_quark_forward = event[iforward].y();
760  if ((find_forward && y_quark_current > y_quark_forward) ||
761  (!find_forward && y_quark_current < y_quark_forward)) {
762  iforward = ip;
763  }
764  }
765  return iforward;
766  }
Here is the caller graph for this function:

◆ get_final_state()

ParticleList smash::StringProcess::get_final_state ( )
inline

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

Returns
ParticleList filled with the final state particles.

Definition at line 773 of file stringprocess.h.

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

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

779 { 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 [2].

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

Definition at line 151 of file stringprocess.cc.

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

◆ append_intermediate_list()

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

append new particle from PYTHIA to a specific particle list

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

Definition at line 805 of file stringprocess.h.

806  {
807  const std::string s = std::to_string(pdgid);
808  PdgCode pythia_code(s);
809  ParticleTypePtr new_type = ParticleType::try_find(pythia_code);
810  if (new_type) {
811  ParticleData new_particle(ParticleType::find(pythia_code));
812  new_particle.set_4momentum(momentum);
813  intermediate_particles.push_back(new_particle);
814  return true;
815  } else {
816  // if the particle does not exist in SMASH the pythia event is rerun
817  return false;
818  }
819  }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ convert_KaonLS()

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

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

Parameters
[out]pythia_idis PDG id to be converted.

Definition at line 825 of file stringprocess.h.

825  {
826  if (pythia_id == 310 || pythia_id == 130) {
827  pythia_id = (random::uniform_int(0, 1) == 0) ? 311 : -311;
828  }
829  }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ quarks_from_diquark()

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

find two quarks from a diquark.

Order does not matter.

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

Definition at line 1686 of file stringprocess.cc.

1687  {
1688  // The 4-digit pdg id should be diquark.
1689  assert((std::abs(diquark) > 1000) && (std::abs(diquark) < 5510) &&
1690  (std::abs(diquark) % 100 < 10));
1691 
1692  // The fourth digit corresponds to the spin degeneracy.
1693  deg_spin = std::abs(diquark) % 10;
1694  // Diquark (anti-diquark) is decomposed into two quarks (antiquarks).
1695  const int sign_anti = diquark > 0 ? 1 : -1;
1696 
1697  // Obtain two quarks (or antiquarks) from the first and second digit.
1698  q1 = sign_anti * (std::abs(diquark) - (std::abs(diquark) % 1000)) / 1000;
1699  q2 = sign_anti * (std::abs(diquark) % 1000 - deg_spin) / 100;
1700 }
Here is the caller graph for this function:

◆ diquark_from_quarks()

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

Construct diquark from two quarks.

Order does not matter.

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

Definition at line 1702 of file stringprocess.cc.

1702  {
1703  assert((q1 > 0 && q2 > 0) || (q1 < 0 && q2 < 0));
1704  if (std::abs(q1) < std::abs(q2)) {
1705  std::swap(q1, q2);
1706  }
1707  int diquark = std::abs(q1 * 1000 + q2 * 100);
1708  /* Adding spin degeneracy = 2S+1. For identical quarks spin cannot be 0
1709  * because of Pauli exclusion principle, so spin 1 is assumed. Otherwise
1710  * S = 0 with probability 1/4 and S = 1 with probability 3/4. */
1711  diquark += (q1 != q2 && random::uniform_int(0, 3) == 0) ? 1 : 3;
1712  return (q1 < 0) ? -diquark : diquark;
1713 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ make_string_ends()

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

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

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

Definition at line 1715 of file stringprocess.cc.

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

◆ set_Vec4()

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

Easy setter of Pythia Vec4 from SMASH.

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

Definition at line 865 of file stringprocess.h.

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

◆ reorient()

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

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

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

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

Definition at line 880 of file stringprocess.h.

881  {
882  ThreeVector three_momentum = evec_basis[0] * particle.pz() +
883  evec_basis[1] * particle.px() +
884  evec_basis[2] * particle.py();
885  return FourVector(particle.e(), three_momentum);
886  }
Here is the caller graph for this function:

◆ fragment_string()

int smash::StringProcess::fragment_string ( int  idq1,
int  idq2,
double  mString,
ThreeVector evecLong,
bool  flip_string_ends,
bool  separate_fragment_baryon,
ParticleList &  intermediate_particles 
)

perform string fragmentation to determine species and momenta of hadrons by implementing PYTHIA 8.2 Andersson:1983ia [2], Sjostrand:2014zea [46].

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

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

◆ fragment_off_hadron()

int smash::StringProcess::fragment_off_hadron ( bool  from_forward,
bool  separate_fragment_baryon,
std::array< ThreeVector, 3 > &  evec_basis,
double &  ppos_string,
double &  pneg_string,
double &  QTrx_string_pos,
double &  QTrx_string_neg,
double &  QTry_string_pos,
double &  QTry_string_neg,
Pythia8::FlavContainer &  flav_string_pos,
Pythia8::FlavContainer &  flav_string_neg,
std::vector< int > &  pdgid_frag,
std::vector< FourVector > &  momentum_frag 
)

Fragment one hadron from a given string configuration if the string mass is above threshold (given by the consituent masses).

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

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

Definition at line 2235 of file stringprocess.cc.

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

◆ get_hadrontype_from_quark()

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

Determines hadron type from valence quark constituents.

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

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

Definition at line 2566 of file stringprocess.cc.

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

◆ get_resonance_from_quark()

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

Definition at line 2654 of file stringprocess.cc.

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

◆ make_lightcone_final_two()

bool smash::StringProcess::make_lightcone_final_two ( bool  separate_fragment_hadron,
double  ppos_string,
double  pneg_string,
double  mTrn_had_forward,
double  mTrn_had_backward,
double &  ppos_had_forward,
double &  ppos_had_backward,
double &  pneg_had_forward,
double &  pneg_had_backward 
)

Determines lightcone momenta of two final hadrons fragmented from a string in the same way as StringFragmentation::finalTwo in StringFragmentation.cc of PYTHIA 8.

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

Definition at line 2780 of file stringprocess.cc.

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

◆ sample_zLund()

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

Sample lightcone momentum fraction according to the LUND fragmentation function.

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

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

Definition at line 2845 of file stringprocess.cc.

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

◆ remake_kinematics_fragments()

bool smash::StringProcess::remake_kinematics_fragments ( Pythia8::Event &  event_fragments,
std::array< ThreeVector, 3 > &  evec_basis,
double  ppos_string,
double  pneg_string,
double  QTrx_string,
double  QTry_string,
double  QTrx_add_pos,
double  QTry_add_pos,
double  QTrx_add_neg,
double  QTry_add_neg 
)
Parameters
[out]event_fragmentsevent record which contains information of particles
[in]evec_basisthree orthonormal basis vectors of which evec_basis[0] is in the longitudinal direction while evec_basis[1] and evec_basis[2] span the transverse plane.
[in]ppos_stringlightcone momentum p^+ of the string
[in]pneg_stringligntcone momentum p^- of the string
[in]QTrx_stringtransverse momentum px of the string
[in]QTry_stringtransverse momentum py of the string
[in]QTrx_add_postransverse momentum px to be added to the most forward hadron
[in]QTry_add_postransverse momentum py to be added to the most forward hadron
[in]QTrx_add_negtransverse momentum px to be added to the most backward hadron
[in]QTry_add_negtransverse momentum py to be added to the most backward hadron

Definition at line 2877 of file stringprocess.cc.

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

◆ shift_rapidity_event()

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

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

y to factor_yrapid * y + diff_yrapid

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

Definition at line 1049 of file stringprocess.h.

1051  {
1052  Pythia8::Vec4 pvec_string_now = Pythia8::Vec4(0., 0., 0., 0.);
1053  // loop over all particles in the record
1054  for (int ipyth = 1; ipyth < event.size(); ipyth++) {
1055  if (!event[ipyth].isFinal()) {
1056  continue;
1057  }
1058 
1059  FourVector p_frag = FourVector(
1060  event[ipyth].e(), event[ipyth].px(),
1061  event[ipyth].py(), event[ipyth].pz());
1062  const double E_frag = p_frag.x0();
1063  const double pl_frag = p_frag.threevec() * evec_basis[0];
1064  const double ppos_frag = (E_frag + pl_frag) * M_SQRT1_2;
1065  const double pneg_frag = (E_frag - pl_frag) * M_SQRT1_2;
1066  const double mTrn_frag = std::sqrt(2. * ppos_frag * pneg_frag);
1067  // evaluate the old momentum rapidity
1068  const double y_frag = 0.5 * std::log(ppos_frag / pneg_frag);
1069 
1070  // obtain the new momentum rapidity
1071  const double y_new_frag = factor_yrapid * y_frag + diff_yrapid;
1072  // compute the new four momentum
1073  const double E_new_frag = mTrn_frag * std::cosh(y_new_frag);
1074  const double pl_new_frag = mTrn_frag * std::sinh(y_new_frag);
1075  ThreeVector mom_new_frag =
1076  p_frag.threevec() + (pl_new_frag - pl_frag) * evec_basis[0];
1077  Pythia8::Vec4 pvec_new_frag = set_Vec4(E_new_frag, mom_new_frag);
1078  event[ipyth].p(pvec_new_frag);
1079  pvec_string_now += pvec_new_frag;
1080  }
1081  event[0].p(pvec_string_now);
1082  event[0].m(pvec_string_now.mCalc());
1083  }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ assign_all_scaling_factors()

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

Assign a cross section scaling factor to all outgoing particles.

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

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

Definition at line 3208 of file stringprocess.cc.

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

◆ find_leading()

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

Find the leading string fragments.

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

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

Definition at line 3191 of file stringprocess.cc.

3192  {
3193  assert(list.size() >= 2);
3194  int end = list.size() - 1;
3195  int i1, i2;
3196  for (i1 = 0;
3197  i1 <= end && !list[i1].pdgcode().contains_enough_valence_quarks(nq1);
3198  i1++) {
3199  }
3200  for (i2 = end;
3201  i2 >= 0 && !list[i2].pdgcode().contains_enough_valence_quarks(nq2);
3202  i2--) {
3203  }
3204  std::pair<int, int> indices(i1, i2);
3205  return indices;
3206 }
Here is the caller graph for this function:

◆ assign_scaling_factor()

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

Assign a cross section scaling factor to the given particle.

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

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

Definition at line 3176 of file stringprocess.cc.

3177  {
3178  int nbaryon = data.pdgcode().baryon_number();
3179  if (nbaryon == 0) {
3180  // Mesons always get a scaling factor of 1/2 since there is never
3181  // a q-qbar pair at the end of a string so nquark is always 1
3182  data.set_cross_section_scaling_factor(0.5 * suppression_factor);
3183  } else if (data.is_baryon()) {
3184  // Leading baryons get a factor of 2/3 if they carry 2
3185  // and 1/3 if they carry 1 of the strings valence quarks
3186  data.set_cross_section_scaling_factor(suppression_factor * nquark /
3187  (3.0 * nbaryon));
3188  }
3189 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ pdg_map_for_pythia()

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

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

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

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

Definition at line 3255 of file stringprocess.cc.

3255  {
3256  PdgCode pdg_mapped(0x0);
3257 
3258  if (pdg.baryon_number() == 1) { // baryon
3259  pdg_mapped = pdg.charge() > 0 ? PdgCode(pdg::p) : PdgCode(pdg::n);
3260  } else if (pdg.baryon_number() == -1) { // antibaryon
3261  pdg_mapped = pdg.charge() < 0 ? PdgCode(-pdg::p) : PdgCode(-pdg::n);
3262  } else if (pdg.is_hadron()) { // meson
3263  if (pdg.charge() >= 0) {
3264  pdg_mapped = PdgCode(pdg::pi_p);
3265  } else {
3266  pdg_mapped = PdgCode(pdg::pi_m);
3267  }
3268  } else if (pdg.is_lepton()) { // lepton
3269  pdg_mapped = pdg.charge() < 0 ? PdgCode(0x11) : PdgCode(-0x11);
3270  } else {
3271  throw std::runtime_error("StringProcess::pdg_map_for_pythia failed.");
3272  }
3273 
3274  return pdg_mapped.get_decimal();
3275 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ getPPosA()

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

Definition at line 1160 of file stringprocess.h.

1160 { 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 1166 of file stringprocess.h.

1166 { 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 1172 of file stringprocess.h.

1172 { 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 1178 of file stringprocess.h.

1178 { return PNegB_;}

◆ get_massA()

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

Definition at line 1184 of file stringprocess.h.

1184 { return massA_;}

◆ get_massB()

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

Definition at line 1190 of file stringprocess.h.

1190 { return massB_;}

◆ get_sqrts()

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

Definition at line 1196 of file stringprocess.h.

1196 { 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 1202 of file stringprocess.h.

1202 { 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 1208 of file stringprocess.h.

1208 { 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 1214 of file stringprocess.h.

1214 { 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 1220 of file stringprocess.h.

1220 { 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 1226 of file stringprocess.h.

1226 { return vcomAB_;}

◆ get_tcoll()

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

Definition at line 1232 of file stringprocess.h.

1232 { 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 [2] eq.

2.45:

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

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

Definition at line 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.

◆ final_state_

ParticleList smash::StringProcess::final_state_
private

final state array which must be accessed after the collision

Definition at line 170 of file stringprocess.h.

◆ hard_map_

pythia_map smash::StringProcess::hard_map_
private

Map object to contain the different pythia objects.

Definition at line 181 of file stringprocess.h.

◆ pythia_hadron_

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

PYTHIA object used in fragmentation.

Definition at line 184 of file stringprocess.h.

◆ pythia_sigmatot_

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

An object to compute cross-sections.

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


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