Version: SMASH-1.6
smash::StringProcess Class Reference

#include <processstring.h>

String excitation processes used in SMASH.

Only one instance of this class should be created.

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

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 46 of file processstring.h.

Collaboration diagram for smash::StringProcess:
[legend]

Public Member Functions

 StringProcess (double string_tension, double time_formation, double gluon_beta, double gluon_pmin, double quark_alpha, double quark_beta, double strange_supp, double diquark_supp, double sigma_perp, double stringz_a_leading, double stringz_b_leading, double stringz_a, double stringz_b, double string_sigma_T, double factor_t_form, bool mass_dependent_formation_times, double prob_proton_to_d_uu, bool separate_fragment_baryon, double popcorn_rate)
 Constructor, initializes pythia. More...
 
void common_setup_pythia (Pythia8::Pythia *pythia_in, double strange_supp, double diquark_supp, double popcorn_rate, double stringz_a, double stringz_b, double string_sigma_T)
 Common setup of PYTHIA objects for soft and hard string routines. More...
 
void init_pythia_hadron_rndm ()
 Set PYTHIA random seeds to be desired values. More...
 
Pythia8::Pythia * get_ptr_pythia_parton ()
 Function to get the PYTHIA object for hard string routine. More...
 
std::array< double, 3 > cross_sections_diffractive (int pdg_a, int pdg_b, double sqrt_s)
 Interface to pythia_sigmatot_ to compute cross-sections of A+B-> different final states Schuler:1993wr. 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. 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, Bleicher:1999xi. More...
 
bool next_NDiffSoft ()
 Soft Non-diffractive process is modelled in accordance with dual-topological approach Capella:1978ig. 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, Bleicher:1999xi 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 partice 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 constitents that need to be converted into other flavors. More...
 
bool restore_constituent (Pythia8::Event &event_intermediate, std::array< std::array< int, 5 >, 2 > &excess_quark, std::array< std::array< int, 5 >, 2 > &excess_antiq)
 Take the intermediate partonic state from PYTHIA event with mapped hadrons and convert constituents into the desired ones according to the excess of quarks and anti-quarks. More...
 
void compose_string_parton (bool find_forward_string, Pythia8::Event &event_intermediate, Pythia8::Event &event_hadronize)
 Identify a set of partons, which are connected to form a color-neutral string, from a given PYTHIA event record. More...
 
void compose_string_junction (bool &find_forward_string, Pythia8::Event &event_intermediate, Pythia8::Event &event_hadronize)
 Identify a set of partons and junction(s), which are connected to form a color-neutral string, from a given PYTHIA event record. More...
 
void find_junction_leg (bool sign_color, std::vector< int > &col, Pythia8::Event &event_intermediate, Pythia8::Event &event_hadronize)
 Identify partons, which are associated with junction legs, from a given PYTHIA event record. More...
 
int get_index_forward (bool find_forward, int np_end, Pythia8::Event &event)
 Obtain index of the most forward or backward particle in a given PYTHIA event record. More...
 
ParticleList get_final_state ()
 a function to get the final state particle list which is called after the collision More...
 
int append_final_state (ParticleList &intermediate_particles, const FourVector &uString, const ThreeVector &evecLong)
 compute the formation time and fill the arrays with final-state particles as described in Andersson:1983ia. 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, Sjostrand:2014zea. 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...
 
double sample_zLund (double a, double b, double mTrn)
 Sample lightcone momentum fraction according to the LUND fragmentation function. 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...
 

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 void assign_all_scaling_factors (int baryon_string, ParticleList &outgoing_particles, const ThreeVector &evecLong, double suppression_factor)
 Assign a cross section scaling factor to all outgoing particles. More...
 
static std::pair< int, int > find_leading (int nq1, int nq2, ParticleList &list)
 Find the leading string fragments. More...
 
static void assign_scaling_factor (int nquark, ParticleData &data, double suppression_factor)
 Assign a cross section scaling factor to the given particle. More...
 
static int pdg_map_for_pythia (PdgCode &pdg)
 Take pdg code and map onto particle specie which can be handled by PYTHIA. More...
 

Private Attributes

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

Constructor & Destructor Documentation

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

Constructor, initializes pythia.

Should only be called once.

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

Definition at line 20 of file processstring.cc.

28  : pmin_gluon_lightcone_(gluon_pmin),
29  pow_fgluon_beta_(gluon_beta),
30  pow_fquark_alpha_(quark_alpha),
31  pow_fquark_beta_(quark_beta),
32  sigma_qperp_(sigma_perp),
33  stringz_a_leading_(stringz_a_leading),
34  stringz_b_leading_(stringz_b_leading),
35  stringz_a_produce_(stringz_a),
36  stringz_b_produce_(stringz_b),
37  kappa_tension_string_(string_tension),
39  time_formation_const_(time_formation),
40  soft_t_form_(factor_t_form),
41  time_collision_(0.),
42  mass_dependent_formation_times_(mass_dependent_formation_times),
43  prob_proton_to_d_uu_(prob_proton_to_d_uu),
44  separate_fragment_baryon_(separate_fragment_baryon) {
45  // setup and initialize pythia for hard string process
46  pythia_parton_ = make_unique<Pythia8::Pythia>(PYTHIA_XML_DIR, false);
47  /* select only non-diffractive events
48  * diffractive ones are implemented in a separate routine */
49  pythia_parton_->readString("SoftQCD:nonDiffractive = on");
50  pythia_parton_->readString("MultipartonInteractions:pTmin = 1.5");
51  pythia_parton_->readString("HadronLevel:all = off");
52  common_setup_pythia(pythia_parton_.get(), strange_supp, diquark_supp,
53  popcorn_rate, stringz_a, stringz_b, string_sigma_T);
54 
55  // setup and initialize pythia for fragmentation
56  pythia_hadron_ = make_unique<Pythia8::Pythia>(PYTHIA_XML_DIR, false);
57  /* turn off all parton-level processes to implement only hadronization */
58  pythia_hadron_->readString("ProcessLevel:all = off");
59  common_setup_pythia(pythia_hadron_.get(), strange_supp, diquark_supp,
60  popcorn_rate, stringz_a, stringz_b, string_sigma_T);
61 
62  /* initialize PYTHIA */
63  pythia_hadron_->init();
64  pythia_sigmatot_.init(&pythia_hadron_->info, pythia_hadron_->settings,
65  &pythia_hadron_->particleData, &pythia_hadron_->rndm);
66  pythia_stringflav_.init(pythia_hadron_->settings,
67  &pythia_hadron_->particleData, &pythia_hadron_->rndm,
68  &pythia_hadron_->info);
69  event_intermediate_.init("intermediate partons",
70  &pythia_hadron_->particleData);
71 
72  for (int imu = 0; imu < 3; imu++) {
73  evecBasisAB_[imu] = ThreeVector(0., 0., 0.);
74  }
75 
76  final_state_.clear();
77 }
double additional_xsec_supp_
additional cross-section suppression factor to take coherence effect into account.
double pmin_gluon_lightcone_
the minimum lightcone momentum scale carried by a gluon [GeV]
Definition: processstring.h:83
std::unique_ptr< Pythia8::Pythia > pythia_hadron_
PYTHIA object used in fragmentation.
double stringz_b_leading_
parameter (StringZ:bLund) for the fragmentation function of leading baryon in soft non-diffractive st...
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...
Pythia8::SigmaTotal pythia_sigmatot_
An object to compute cross-sections.
std::unique_ptr< Pythia8::Pythia > pythia_parton_
PYTHIA object used in hard string routine.
double stringz_b_produce_
parameter (StringZ:bLund) for the fragmentation function of other (produced) hadrons in soft non-diff...
Pythia8::Event event_intermediate_
event record for intermediate partonic state in the hard string routine
double kappa_tension_string_
string tension [GeV/fm]
double pow_fquark_alpha_
parameter for the quark distribution function
Definition: processstring.h:93
double stringz_a_produce_
parameter (StringZ:aLund) for the fragmentation function of other (produced) hadrons in soft non-diff...
bool separate_fragment_baryon_
Whether to use a separate fragmentation function for leading baryons.
ParticleList final_state_
final state array which must be accessed after the collision
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.
Pythia8::StringFlav pythia_stringflav_
An object for the flavor selection in string fragmentation in the case of separate fragmentation func...
double time_collision_
time of collision in the computational frame [fm]
double soft_t_form_
factor to be multiplied to formation times in soft strings
double pow_fgluon_beta_
parameter for the gluon distribution function
Definition: processstring.h:88
bool mass_dependent_formation_times_
Whether the formation time should depend on the mass of the fragment according to Andersson:1983ia eq...
std::array< ThreeVector, 3 > evecBasisAB_
Orthonormal basis vectors in the center of mass frame, where the 0th one is parallel to momentum of i...
Definition: processstring.h:77
double sigma_qperp_
Transverse momentum spread of the excited strings.
double stringz_a_leading_
parameter (StringZ:aLund) for the fragmentation function of leading baryon in soft non-diffractive st...
double time_formation_const_
constant proper time in the case of constant formation time [fm]
double pow_fquark_beta_
parameter for the quark distribution function
Definition: processstring.h:98

Here is the call graph for this function:

Member Function Documentation

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

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

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

Definition at line 79 of file processstring.cc.

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

Here is the call graph for this function:

Here is the caller graph for this function:

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 276 of file processstring.h.

276  {
277  const auto &log = logger<LogArea::Pythia>();
278  const int seed_new =
280 
281  pythia_hadron_->rndm.init(seed_new);
282  log.debug("pythia_hadron_ : rndm is initialized with seed ", seed_new);
283  }
std::unique_ptr< Pythia8::Pythia > pythia_hadron_
PYTHIA object used in fragmentation.
T uniform_int(T min, T max)
Definition: random.h:100
constexpr int maximum_rndm_seed_in_pythia
The maximum value of the random seed used in PYTHIA.
Definition: constants.h:113

Here is the call graph for this function:

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

Function to get the PYTHIA object for hard string routine.

Returns
pointer to the PYTHIA object used in hard string routine

Definition at line 291 of file processstring.h.

291 { return pythia_parton_.get(); }
std::unique_ptr< Pythia8::Pythia > pythia_parton_
PYTHIA object used in hard string routine.
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.

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

Definition at line 302 of file processstring.h.

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

Here is the caller graph for this function:

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

set the minimum lightcone momentum scale carried by gluon.

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

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

Parameters
p_light_cone_mina value that we want to use for pmin_gluon_lightcone_.

Definition at line 338 of file processstring.h.

338  {
339  pmin_gluon_lightcone_ = p_light_cone_min;
340  }
double pmin_gluon_lightcone_
the minimum lightcone momentum scale carried by a gluon [GeV]
Definition: processstring.h:83
void smash::StringProcess::set_pow_fgluon ( double  betapow)
inline

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

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

Definition at line 348 of file processstring.h.

348 { pow_fgluon_beta_ = betapow; }
double pow_fgluon_beta_
parameter for the gluon distribution function
Definition: processstring.h:88
void smash::StringProcess::set_pow_fquark ( double  alphapow,
double  betapow 
)
inline

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

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

Definition at line 357 of file processstring.h.

357  {
358  pow_fquark_alpha_ = alphapow;
359  pow_fquark_beta_ = betapow;
360  }
double pow_fquark_alpha_
parameter for the quark distribution function
Definition: processstring.h:93
double pow_fquark_beta_
parameter for the quark distribution function
Definition: processstring.h:98
void smash::StringProcess::set_sigma_qperp_ ( double  sigma_qperp)
inline

set the average amount of transverse momentum transfer sigma_qperp_.

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

Definition at line 365 of file processstring.h.

365 { sigma_qperp_ = sigma_qperp; }
double sigma_qperp_
Transverse momentum spread of the excited strings.
void smash::StringProcess::set_tension_string ( double  kappa_string)
inline

set the string tension, which is used in append_final_state.

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

Definition at line 370 of file processstring.h.

370  {
371  kappa_tension_string_ = kappa_string;
372  }
double kappa_tension_string_
string tension [GeV/fm]

Here is the call graph for this function:

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 199 of file processstring.cc.

199  {
200  PDGcodes_[0] = incoming[0].pdgcode();
201  PDGcodes_[1] = incoming[1].pdgcode();
202  massA_ = incoming[0].effective_mass();
203  massB_ = incoming[1].effective_mass();
204 
205  plab_[0] = incoming[0].momentum();
206  plab_[1] = incoming[1].momentum();
207 
208  // compute sqrts and velocity of the center of mass.
209  sqrtsAB_ = (plab_[0] + plab_[1]).abs();
210  ucomAB_ = (plab_[0] + plab_[1]) / sqrtsAB_;
212 
213  pcom_[0] = plab_[0].LorentzBoost(vcomAB_);
214  pcom_[1] = plab_[1].LorentzBoost(vcomAB_);
215 
216  const double pabscomAB = pCM(sqrtsAB_, massA_, massB_);
217  ThreeVector evec_coll = pcom_[0].threevec() / pabscomAB;
219 
221 
222  time_collision_ = tcoll;
223 }
std::array< FourVector, 2 > plab_
momenta of incoming particles in the lab frame [GeV]
Definition: processstring.h:66
std::array< PdgCode, 2 > PDGcodes_
PdgCodes of incoming particles.
Definition: processstring.h:64
std::array< FourVector, 2 > pcom_
momenta of incoming particles in the center of mass frame [GeV]
Definition: processstring.h:68
double sqrtsAB_
sqrt of Mandelstam variable s of collision [GeV]
Definition: processstring.h:62
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 ...
void compute_incoming_lightcone_momenta()
compute the lightcone momenta of incoming particles where the longitudinal direction is set to be sam...
ThreeVector velocity() const
Get the velocity (3-vector divided by zero component).
Definition: fourvector.h:310
ThreeVector vcomAB_
velocity three vector of the center of mass in the lab frame
Definition: processstring.h:72
FourVector ucomAB_
velocity four vector of the center of mass in the lab frame
Definition: processstring.h:70
double time_collision_
time of collision in the computational frame [fm]
std::array< ThreeVector, 3 > evecBasisAB_
Orthonormal basis vectors in the center of mass frame, where the 0th one is parallel to momentum of i...
Definition: processstring.h:77
T pCM(const T sqrts, const T mass_a, const T mass_b) noexcept
Definition: kinematics.h:79
double massB_
mass of incoming particle B [GeV]
Definition: processstring.h:60
double massA_
mass of incoming particle A [GeV]
Definition: processstring.h:58

Here is the call graph for this function:

Here is the caller graph for this function:

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

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

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

Definition at line 1615 of file processstring.cc.

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

Here is the call graph for this function:

Here is the caller graph for this function:

void smash::StringProcess::compute_incoming_lightcone_momenta ( )

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

Definition at line 1664 of file processstring.cc.

1664  {
1665  PPosA_ = (pcom_[0].x0() + evecBasisAB_[0] * pcom_[0].threevec()) * M_SQRT1_2;
1666  PNegA_ = (pcom_[0].x0() - evecBasisAB_[0] * pcom_[0].threevec()) * M_SQRT1_2;
1667  PPosB_ = (pcom_[1].x0() + evecBasisAB_[0] * pcom_[1].threevec()) * M_SQRT1_2;
1668  PNegB_ = (pcom_[1].x0() - evecBasisAB_[0] * pcom_[1].threevec()) * M_SQRT1_2;
1669 }
double PPosA_
forward lightcone momentum p^{+} of incoming particle A in CM-frame [GeV]
Definition: processstring.h:50
double PNegB_
backward lightcone momentum p^{-} of incoming particle B in CM-frame [GeV]
Definition: processstring.h:56
std::array< FourVector, 2 > pcom_
momenta of incoming particles in the center of mass frame [GeV]
Definition: processstring.h:68
double PNegA_
backward lightcone momentum p^{-} of incoming particle A in CM-frame [GeV]
Definition: processstring.h:54
double PPosB_
forward lightcone momentum p^{+} of incoming particle B in CM-frame [GeV]
Definition: processstring.h:52
std::array< ThreeVector, 3 > evecBasisAB_
Orthonormal basis vectors in the center of mass frame, where the 0th one is parallel to momentum of i...
Definition: processstring.h:77

Here is the caller graph for this function:

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 310 of file processstring.cc.

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

Here is the call graph for this function:

Here is the caller graph for this function:

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 347 of file processstring.cc.

352  {
353  const std::array<FourVector, 2> ustr_com = {pstr_com[0] / m_str[0],
354  pstr_com[1] / m_str[1]};
355  for (int i = 0; i < 2; i++) {
356  ParticleList new_intermediate_particles;
357 
358  // determine direction in which string i is stretched.
359  ThreeVector evec = evec_str[i];
360  // perform fragmentation and add particles to final_state.
361  int nfrag = fragment_string(quarks[i][0], quarks[i][1], m_str[i], evec,
362  flip_string_ends, separate_fragment_baryon,
363  new_intermediate_particles);
364  if (nfrag <= 0) {
365  NpartString_[i] = 0;
366  return false;
367  }
368  NpartString_[i] =
369  append_final_state(new_intermediate_particles, ustr_com[i], evec);
370  assert(nfrag == NpartString_[i]);
371  }
372  if ((NpartString_[0] > 0) && (NpartString_[1] > 0)) {
374  return true;
375  }
376  return false;
377 }
std::array< int, 2 > NpartString_
number of particles fragmented from strings
Definition: processstring.h:81
int NpartFinal_
total number of final state particles
Definition: processstring.h:79
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...
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...

Here is the call graph for this function:

Here is the caller graph for this function:

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

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

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 228 of file processstring.cc.

228  {
229  NpartFinal_ = 0;
230  NpartString_[0] = 0;
231  NpartString_[1] = 0;
232  final_state_.clear();
233 
234  double massH = is_AB_to_AX ? massA_ : massB_;
235  double mstrMin = is_AB_to_AX ? massB_ : massA_;
236  double mstrMax = sqrtsAB_ - massH;
237 
238  int idqX1, idqX2;
239  double QTrn, QTrx, QTry;
240  double pabscomHX_sqr, massX;
241 
242  // decompose hadron into quarks
243  make_string_ends(is_AB_to_AX ? PDGcodes_[1] : PDGcodes_[0], idqX1, idqX2,
245  // string mass must be larger than threshold set by PYTHIA.
246  mstrMin = pythia_hadron_->particleData.m0(idqX1) +
247  pythia_hadron_->particleData.m0(idqX2);
248  // this threshold cannot be larger than maximum of allowed string mass.
249  if (mstrMin > mstrMax) {
250  return false;
251  }
252  // sample the transverse momentum transfer
253  QTrx = random::normal(0., sigma_qperp_ * M_SQRT1_2);
254  QTry = random::normal(0., sigma_qperp_ * M_SQRT1_2);
255  QTrn = std::sqrt(QTrx * QTrx + QTry * QTry);
256  /* sample the string mass and
257  * evaluate the three-momenta of hadron and string. */
258  massX = random::power(-1.0, mstrMin, mstrMax);
259  pabscomHX_sqr = pCM_sqr(sqrtsAB_, massH, massX);
260  /* magnitude of the three momentum must be larger
261  * than the transverse momentum. */
262  const bool foundPabsX = pabscomHX_sqr > QTrn * QTrn;
263 
264  if (!foundPabsX) {
265  return false;
266  }
267  double sign_direction = is_AB_to_AX ? 1. : -1.;
268  // determine three momentum of the final state hadron
269  const ThreeVector cm_momentum =
270  sign_direction *
271  (evecBasisAB_[0] * std::sqrt(pabscomHX_sqr - QTrn * QTrn) +
272  evecBasisAB_[1] * QTrx + evecBasisAB_[2] * QTry);
273  const FourVector pstrHcom(std::sqrt(pabscomHX_sqr + massH * massH),
274  cm_momentum);
275  const FourVector pstrXcom(std::sqrt(pabscomHX_sqr + massX * massX),
276  -cm_momentum);
277 
278  const FourVector ustrXcom = pstrXcom / massX;
279  /* determine direction in which the string is stretched.
280  * this is set to be same with the the collision axis
281  * in the center of mass frame. */
282  const ThreeVector threeMomentum =
283  is_AB_to_AX ? pcom_[1].threevec() : pcom_[0].threevec();
284  const FourVector pnull = FourVector(threeMomentum.abs(), threeMomentum);
285  const FourVector prs = pnull.LorentzBoost(ustrXcom.velocity());
286  ThreeVector evec = prs.threevec() / prs.threevec().abs();
287  // perform fragmentation and add particles to final_state.
288  ParticleList new_intermediate_particles;
289  int nfrag = fragment_string(idqX1, idqX2, massX, evec, true, false,
290  new_intermediate_particles);
291  if (nfrag < 1) {
292  NpartString_[0] = 0;
293  return false;
294  }
295  NpartString_[0] =
296  append_final_state(new_intermediate_particles, ustrXcom, evec);
297 
298  NpartString_[1] = 1;
299  PdgCode hadron_code = is_AB_to_AX ? PDGcodes_[0] : PDGcodes_[1];
300  ParticleData new_particle(ParticleType::find(hadron_code));
301  new_particle.set_4momentum(pstrHcom);
302  new_particle.set_cross_section_scaling_factor(1.);
303  new_particle.set_formation_time(time_collision_);
304  final_state_.push_back(new_particle);
305 
307  return true;
308 }
std::array< int, 2 > NpartString_
number of particles fragmented from strings
Definition: processstring.h:81
int NpartFinal_
total number of final state particles
Definition: processstring.h:79
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.
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...
std::unique_ptr< Pythia8::Pythia > pythia_hadron_
PYTHIA object used in fragmentation.
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...
T pCM_sqr(const T sqrts, const T mass_a, const T mass_b) noexcept
Definition: kinematics.h:91
std::array< PdgCode, 2 > PDGcodes_
PdgCodes of incoming particles.
Definition: processstring.h:64
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...
std::array< FourVector, 2 > pcom_
momenta of incoming particles in the center of mass frame [GeV]
Definition: processstring.h:68
double sqrtsAB_
sqrt of Mandelstam variable s of collision [GeV]
Definition: processstring.h:62
static const ParticleType & find(PdgCode pdgcode)
Returns the ParticleType object for the given pdgcode.
ParticleList final_state_
final state array which must be accessed after the collision
double time_collision_
time of collision in the computational frame [fm]
T power(T n, T xMin, T xMax)
Draws a random number according to a power-law distribution ~ x^n.
Definition: random.h:203
std::array< ThreeVector, 3 > evecBasisAB_
Orthonormal basis vectors in the center of mass frame, where the 0th one is parallel to momentum of i...
Definition: processstring.h:77
double normal(const T &mean, const T &sigma)
Returns a random number drawn from a normal distribution.
Definition: random.h:250
double sigma_qperp_
Transverse momentum spread of the excited strings.
double massB_
mass of incoming particle B [GeV]
Definition: processstring.h:60
double massA_
mass of incoming particle A [GeV]
Definition: processstring.h:58

Here is the call graph for this function:

Here is the caller graph for this function:

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, Bleicher:1999xi.

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

Returns
whether the process is successfully implemented.

Definition at line 380 of file processstring.cc.

380  {
381  NpartFinal_ = 0;
382  NpartString_[0] = 0;
383  NpartString_[1] = 0;
384  final_state_.clear();
385 
386  std::array<std::array<int, 2>, 2> quarks;
387  std::array<FourVector, 2> pstr_com;
388  std::array<double, 2> m_str;
389  std::array<ThreeVector, 2> evec_str;
390  ThreeVector threeMomentum;
391 
392  // decompose hadron into quark (and diquark) contents
393  make_string_ends(PDGcodes_[0], quarks[0][0], quarks[0][1],
395  make_string_ends(PDGcodes_[1], quarks[1][0], quarks[1][1],
397  // sample the lightcone momentum fraction carried by gluons
398  const double xmin_gluon_fraction = pmin_gluon_lightcone_ / sqrtsAB_;
399  const double xfracA =
400  random::beta_a0(xmin_gluon_fraction, pow_fgluon_beta_ + 1.);
401  const double xfracB =
402  random::beta_a0(xmin_gluon_fraction, pow_fgluon_beta_ + 1.);
403  // sample the transverse momentum transfer
404  const double QTrx = random::normal(0., sigma_qperp_ * M_SQRT1_2);
405  const double QTry = random::normal(0., sigma_qperp_ * M_SQRT1_2);
406  const double QTrn = std::sqrt(QTrx * QTrx + QTry * QTry);
407  // evaluate the lightcone momentum transfer
408  const double QPos = -QTrn * QTrn / (2. * xfracB * PNegB_);
409  const double QNeg = QTrn * QTrn / (2. * xfracA * PPosA_);
410  // compute four-momentum of string 1
411  threeMomentum =
412  evecBasisAB_[0] * (PPosA_ + QPos - PNegA_ - QNeg) * M_SQRT1_2 +
413  evecBasisAB_[1] * QTrx + evecBasisAB_[2] * QTry;
414  pstr_com[0] =
415  FourVector((PPosA_ + QPos + PNegA_ + QNeg) * M_SQRT1_2, threeMomentum);
416  // compute four-momentum of string 2
417  threeMomentum =
418  evecBasisAB_[0] * (PPosB_ - QPos - PNegB_ + QNeg) * M_SQRT1_2 -
419  evecBasisAB_[1] * QTrx - evecBasisAB_[2] * QTry;
420  pstr_com[1] =
421  FourVector((PPosB_ - QPos + PNegB_ - QNeg) * M_SQRT1_2, threeMomentum);
422 
423  const bool found_masses =
424  set_mass_and_direction_2strings(quarks, pstr_com, m_str, evec_str);
425  if (!found_masses) {
426  return false;
427  }
428  const bool flip_string_ends = true;
429  const bool success = make_final_state_2strings(
430  quarks, pstr_com, m_str, evec_str, flip_string_ends, false);
431  return success;
432 }
std::array< int, 2 > NpartString_
number of particles fragmented from strings
Definition: processstring.h:81
double PPosA_
forward lightcone momentum p^{+} of incoming particle A in CM-frame [GeV]
Definition: processstring.h:50
T beta_a0(T xmin, T b)
Draws a random number from a beta-distribution with a = 0.
Definition: random.h:351
double pmin_gluon_lightcone_
the minimum lightcone momentum scale carried by a gluon [GeV]
Definition: processstring.h:83
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.
int NpartFinal_
total number of final state particles
Definition: processstring.h:79
static void make_string_ends(const PdgCode &pdgcode_in, int &idq1, int &idq2, double xi)
make a random selection to determine partonic contents at the string ends.
std::array< PdgCode, 2 > PDGcodes_
PdgCodes of incoming particles.
Definition: processstring.h:64
double prob_proton_to_d_uu_
Probability of splitting a nucleon into the quark flavour it has only once and a diquark it has twice...
double PNegB_
backward lightcone momentum p^{-} of incoming particle B in CM-frame [GeV]
Definition: processstring.h:56
double sqrtsAB_
sqrt of Mandelstam variable s of collision [GeV]
Definition: processstring.h:62
ParticleList final_state_
final state array which must be accessed after the collision
double PNegA_
backward lightcone momentum p^{-} of incoming particle A in CM-frame [GeV]
Definition: processstring.h:54
double PPosB_
forward lightcone momentum p^{+} of incoming particle B in CM-frame [GeV]
Definition: processstring.h:52
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.
double pow_fgluon_beta_
parameter for the gluon distribution function
Definition: processstring.h:88
std::array< ThreeVector, 3 > evecBasisAB_
Orthonormal basis vectors in the center of mass frame, where the 0th one is parallel to momentum of i...
Definition: processstring.h:77
double normal(const T &mean, const T &sigma)
Returns a random number drawn from a normal distribution.
Definition: random.h:250
double sigma_qperp_
Transverse momentum spread of the excited strings.

Here is the call graph for this function:

Here is the caller graph for this function:

bool smash::StringProcess::next_NDiffSoft ( )

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

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, Bleicher:1999xi.

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

Definition at line 435 of file processstring.cc.

435  {
436  NpartFinal_ = 0;
437  NpartString_[0] = 0;
438  NpartString_[1] = 0;
439  final_state_.clear();
440 
441  std::array<std::array<int, 2>, 2> quarks;
442  std::array<FourVector, 2> pstr_com;
443  std::array<double, 2> m_str;
444  std::array<ThreeVector, 2> evec_str;
445 
446  // decompose hadron into quark (and diquark) contents
447  int idqA1, idqA2, idqB1, idqB2;
450 
451  const int bar_a = PDGcodes_[0].baryon_number(),
452  bar_b = PDGcodes_[1].baryon_number();
453  if (bar_a == 1 || // baryon-baryon, baryon-meson, baryon-antibaryon
454  (bar_a == 0 && bar_b == 1) || // meson-baryon
455  (bar_a == 0 && bar_b == 0)) { // meson-meson
456  quarks[0][0] = idqB1;
457  quarks[0][1] = idqA2;
458  quarks[1][0] = idqA1;
459  quarks[1][1] = idqB2;
460  } else if (((bar_a == 0) && (bar_b == -1)) || // meson-antibaryon
461  (bar_a == -1)) { // antibaryon-baryon, antibaryon-meson,
462  // antibaryon-antibaryon
463  quarks[0][0] = idqA1;
464  quarks[0][1] = idqB2;
465  quarks[1][0] = idqB1;
466  quarks[1][1] = idqA2;
467  } else {
468  std::stringstream ss;
469  ss << " StringProcess::next_NDiff : baryonA = " << bar_a
470  << ", baryonB = " << bar_b;
471  throw std::runtime_error(ss.str());
472  }
473  // sample the lightcone momentum fraction carried by quarks
474  const double xfracA = random::beta(pow_fquark_alpha_, pow_fquark_beta_);
475  const double xfracB = random::beta(pow_fquark_alpha_, pow_fquark_beta_);
476  // sample the transverse momentum transfer
477  const double QTrx = random::normal(0., sigma_qperp_ * M_SQRT1_2);
478  const double QTry = random::normal(0., sigma_qperp_ * M_SQRT1_2);
479  const double QTrn = std::sqrt(QTrx * QTrx + QTry * QTry);
480  // evaluate the lightcone momentum transfer
481  const double QPos = -QTrn * QTrn / (2. * xfracB * PNegB_);
482  const double QNeg = QTrn * QTrn / (2. * xfracA * PPosA_);
483  const double dPPos = -xfracA * PPosA_ - QPos;
484  const double dPNeg = xfracB * PNegB_ - QNeg;
485  // compute four-momentum of string 1
486  ThreeVector threeMomentum =
487  evecBasisAB_[0] * (PPosA_ + dPPos - PNegA_ - dPNeg) * M_SQRT1_2 +
488  evecBasisAB_[1] * QTrx + evecBasisAB_[2] * QTry;
489  pstr_com[0] =
490  FourVector((PPosA_ + dPPos + PNegA_ + dPNeg) * M_SQRT1_2, threeMomentum);
491  m_str[0] = pstr_com[0].sqr();
492  // compute four-momentum of string 2
493  threeMomentum =
494  evecBasisAB_[0] * (PPosB_ - dPPos - PNegB_ + dPNeg) * M_SQRT1_2 -
495  evecBasisAB_[1] * QTrx - evecBasisAB_[2] * QTry;
496  pstr_com[1] =
497  FourVector((PPosB_ - dPPos + PNegB_ - dPNeg) * M_SQRT1_2, threeMomentum);
498 
499  const bool found_masses =
500  set_mass_and_direction_2strings(quarks, pstr_com, m_str, evec_str);
501  if (!found_masses) {
502  return false;
503  }
504  const bool flip_string_ends = false;
505  const bool success =
506  make_final_state_2strings(quarks, pstr_com, m_str, evec_str,
507  flip_string_ends, separate_fragment_baryon_);
508  return success;
509 }
std::array< int, 2 > NpartString_
number of particles fragmented from strings
Definition: processstring.h:81
double PPosA_
forward lightcone momentum p^{+} of incoming particle A in CM-frame [GeV]
Definition: processstring.h:50
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.
int NpartFinal_
total number of final state particles
Definition: processstring.h:79
static void make_string_ends(const PdgCode &pdgcode_in, int &idq1, int &idq2, double xi)
make a random selection to determine partonic contents at the string ends.
std::array< PdgCode, 2 > PDGcodes_
PdgCodes of incoming particles.
Definition: processstring.h:64
double prob_proton_to_d_uu_
Probability of splitting a nucleon into the quark flavour it has only once and a diquark it has twice...
double PNegB_
backward lightcone momentum p^{-} of incoming particle B in CM-frame [GeV]
Definition: processstring.h:56
double pow_fquark_alpha_
parameter for the quark distribution function
Definition: processstring.h:93
bool separate_fragment_baryon_
Whether to use a separate fragmentation function for leading baryons.
ParticleList final_state_
final state array which must be accessed after the collision
double PNegA_
backward lightcone momentum p^{-} of incoming particle A in CM-frame [GeV]
Definition: processstring.h:54
double PPosB_
forward lightcone momentum p^{+} of incoming particle B in CM-frame [GeV]
Definition: processstring.h:52
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.
std::array< ThreeVector, 3 > evecBasisAB_
Orthonormal basis vectors in the center of mass frame, where the 0th one is parallel to momentum of i...
Definition: processstring.h:77
double normal(const T &mean, const T &sigma)
Returns a random number drawn from a normal distribution.
Definition: random.h:250
double sigma_qperp_
Transverse momentum spread of the excited strings.
T beta(T a, T b)
Draws a random number from a beta-distribution, where probability density of is .
Definition: random.h:329
double pow_fquark_beta_
parameter for the quark distribution function
Definition: processstring.h:98

Here is the call graph for this function:

Here is the caller graph for this function:

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 512 of file processstring.cc.

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

Here is the call graph for this function:

Here is the caller graph for this function:

bool smash::StringProcess::next_BBbarAnn ( )

Baryon-antibaryon annihilation process Based on what UrQMD Bass:1998ca, Bleicher:1999xi 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 1503 of file processstring.cc.

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

Here is the call graph for this function:

Here is the caller graph for this function:

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 752 of file processstring.cc.

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

Here is the call graph for this function:

Here is the caller graph for this function:

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

Convert a partonic PYTHIA partice 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 786 of file processstring.cc.

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

Here is the call graph for this function:

Here is the caller graph for this function:

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 872 of file processstring.cc.

874  {
875  for (int iflav = 0; iflav < 5; iflav++) {
876  nquark_total[iflav] = 0;
877  nantiq_total[iflav] = 0;
878  }
879 
880  for (int ip = 1; ip < event_intermediate.size(); ip++) {
881  if (!event_intermediate[ip].isFinal()) {
882  continue;
883  }
884  const int pdgid = event_intermediate[ip].id();
885  if (pdgid > 0) {
886  // quarks
887  for (int iflav = 0; iflav < 5; iflav++) {
888  nquark_total[iflav] +=
889  pythia_hadron_->particleData.nQuarksInCode(pdgid, iflav + 1);
890  }
891  } else {
892  // antiquarks
893  for (int iflav = 0; iflav < 5; iflav++) {
894  nantiq_total[iflav] += pythia_hadron_->particleData.nQuarksInCode(
895  std::abs(pdgid), iflav + 1);
896  }
897  }
898  }
899 }
std::unique_ptr< Pythia8::Pythia > pythia_hadron_
PYTHIA object used in fragmentation.

Here is the caller graph for this function:

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 901 of file processstring.cc.

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

Here is the call graph for this function:

Here is the caller graph for this function:

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 constitents 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 1035 of file processstring.cc.

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

Here is the caller graph for this function:

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

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

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

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

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

Definition at line 1094 of file processstring.cc.

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

Here is the call graph for this function:

Here is the caller graph for this function:

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 1247 of file processstring.cc.

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

Here is the call graph for this function:

Here is the caller graph for this function:

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 1335 of file processstring.cc.

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

Here is the call graph for this function:

Here is the caller graph for this function:

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 1440 of file processstring.cc.

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

Here is the caller graph for this function:

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

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

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

Definition at line 747 of file processstring.h.

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

Here is the caller graph for this function:

ParticleList smash::StringProcess::get_final_state ( )
inline

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

Returns
ParticleList filled with the final state particles.

Definition at line 766 of file processstring.h.

766 { return final_state_; }
ParticleList final_state_
final state array which must be accessed after the collision

Here is the call graph for this function:

Here is the caller graph for this function:

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.

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 143 of file processstring.cc.

145  {
146  int nfrag = 0;
147  int bstring = 0;
148 
149  for (ParticleData &data : intermediate_particles) {
150  nfrag += 1;
151  bstring += data.pdgcode().baryon_number();
152  }
153  assert(nfrag > 0);
154 
155  /* compute the cross section scaling factor for leading hadrons
156  * based on the number of valence quarks. */
157  assign_all_scaling_factors(bstring, intermediate_particles, evecLong,
159 
160  // Velocity three-vector to perform Lorentz boost.
161  const ThreeVector vstring = uString.velocity();
162 
163  // compute the formation times of hadrons
164  for (int i = 0; i < nfrag; i++) {
165  ThreeVector velocity = intermediate_particles[i].momentum().velocity();
166  double gamma = 1. / intermediate_particles[i].inverse_gamma();
167  // boost 4-momentum into the center of mass frame
168  FourVector momentum =
169  intermediate_particles[i].momentum().LorentzBoost(-vstring);
170  intermediate_particles[i].set_4momentum(momentum);
171 
173  // set the formation time and position in the rest frame of string
174  double tau_prod = M_SQRT2 * intermediate_particles[i].effective_mass() /
176  double t_prod = tau_prod * gamma;
177  FourVector fragment_position = FourVector(t_prod, t_prod * velocity);
178  /* boost formation position into the center of mass frame
179  * and then into the lab frame */
180  fragment_position = fragment_position.LorentzBoost(-vstring);
181  fragment_position = fragment_position.LorentzBoost(-vcomAB_);
182  intermediate_particles[i].set_slow_formation_times(
184  soft_t_form_ * fragment_position.x0() + time_collision_);
185  } else {
186  ThreeVector v_calc = momentum.LorentzBoost(-vcomAB_).velocity();
187  double gamma_factor = 1.0 / std::sqrt(1 - (v_calc).sqr());
188  intermediate_particles[i].set_slow_formation_times(
190  time_formation_const_ * gamma_factor + time_collision_);
191  }
192 
193  final_state_.push_back(intermediate_particles[i]);
194  }
195 
196  return nfrag;
197 }
double additional_xsec_supp_
additional cross-section suppression factor to take coherence effect into account.
double kappa_tension_string_
string tension [GeV/fm]
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.
ThreeVector vcomAB_
velocity three vector of the center of mass in the lab frame
Definition: processstring.h:72
ParticleList final_state_
final state array which must be accessed after the collision
double time_collision_
time of collision in the computational frame [fm]
double soft_t_form_
factor to be multiplied to formation times in soft strings
bool mass_dependent_formation_times_
Whether the formation time should depend on the mass of the fragment according to Andersson:1983ia eq...
double time_formation_const_
constant proper time in the case of constant formation time [fm]

Here is the call graph for this function:

Here is the caller graph for this function:

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

append new particle from PYTHIA to a specific particle list

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

Definition at line 792 of file processstring.h.

793  {
794  const std::string s = std::to_string(pdgid);
795  PdgCode pythia_code(s);
796  ParticleData new_particle(ParticleType::find(pythia_code));
797  new_particle.set_4momentum(momentum);
798  intermediate_particles.push_back(new_particle);
799  return true;
800  }
static const ParticleType & find(PdgCode pdgcode)
Returns the ParticleType object for the given pdgcode.

Here is the call graph for this function:

Here is the caller graph for this function:

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

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

Parameters
[out]pythia_idis PDG id to be converted.

Definition at line 806 of file processstring.h.

806  {
807  if (pythia_id == 310 || pythia_id == 130) {
808  pythia_id = (random::uniform_int(0, 1) == 0) ? 311 : -311;
809  }
810  }
T uniform_int(T min, T max)
Definition: random.h:100

Here is the call graph for this function:

Here is the caller graph for this function:

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

find two quarks from a diquark.

Order does not matter.

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

Definition at line 1671 of file processstring.cc.

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

Here is the caller graph for this function:

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

Construct diquark from two quarks.

Order does not matter.

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

Definition at line 1687 of file processstring.cc.

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

Here is the call graph for this function:

Here is the caller graph for this function:

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

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

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

Definition at line 1700 of file processstring.cc.

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

Here is the call graph for this function:

Here is the caller graph for this function:

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

Easy setter of Pythia Vec4 from SMASH.

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

Definition at line 844 of file processstring.h.

844  {
845  return Pythia8::Vec4(mom.x1(), mom.x2(), mom.x3(), energy);
846  }

Here is the call graph for this function:

Here is the caller graph for this function:

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

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

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

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

Definition at line 859 of file processstring.h.

860  {
861  ThreeVector three_momentum = evec_basis[0] * particle.pz() +
862  evec_basis[1] * particle.px() +
863  evec_basis[2] * particle.py();
864  return FourVector(particle.e(), three_momentum);
865  }

Here is the call graph for this function:

Here is the caller graph for this function:

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, Sjostrand:2014zea.

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

Definition at line 1748 of file processstring.cc.

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

Here is the call graph for this function:

Here is the caller graph for this function:

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 2218 of file processstring.cc.

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

Here is the call graph for this function:

Here is the caller graph for this function:

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 2546 of file processstring.cc.

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

Here is the call graph for this function:

Here is the caller graph for this function:

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 2634 of file processstring.cc.

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

Here is the call graph for this function:

Here is the caller graph for this function:

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 2761 of file processstring.cc.

2765  {
2766  const double mTsqr_string = 2. * ppos_string * pneg_string;
2767  if (mTsqr_string < 0.) {
2768  return false;
2769  }
2770  const double mTrn_string = std::sqrt(mTsqr_string);
2771  if (mTrn_string < mTrn_had_forward + mTrn_had_backward) {
2772  return false;
2773  }
2774 
2775  // square of transvere mass of the forward hadron
2776  const double mTsqr_had_forward = mTrn_had_forward * mTrn_had_forward;
2777  // square of transvere mass of the backward hadron
2778  const double mTsqr_had_backward = mTrn_had_backward * mTrn_had_backward;
2779 
2780  /* The following part determines lightcone momentum fraction of p^+
2781  * carried by each hadron.
2782  * Lightcone momenta of the forward and backward hadrons are
2783  * p^+ forward = (xe_pos + xpz_pos) * p^+ string,
2784  * p^- forward = (xe_pos - xpz_pos) * p^- string,
2785  * p^+ backward = (xe_neg - xpz_pos) * p^+ string and
2786  * p^- backward = (xe_neg + xpz_pos) * p^- string.
2787  * where xe_pos and xe_neg satisfy xe_pos + xe_neg = 1.
2788  * Then evaluate xe_pos, xe_neg and xpz_pos in terms of
2789  * the transverse masses of hadrons and string. */
2790 
2791  // Express xe_pos and xe_neg in terms of the transverse masses.
2792  const double xm_diff =
2793  (mTsqr_had_forward - mTsqr_had_backward) / mTsqr_string;
2794  const double xe_pos = 0.5 * (1. + xm_diff);
2795  const double xe_neg = 0.5 * (1. - xm_diff);
2796 
2797  // Express xpz_pos in terms of the transverse masses.
2798  const double lambda_sqr =
2799  pow_int(mTsqr_string - mTsqr_had_forward - mTsqr_had_backward, 2) -
2800  4. * mTsqr_had_forward * mTsqr_had_backward;
2801  if (lambda_sqr <= 0.) {
2802  return false;
2803  }
2804  const double lambda = std::sqrt(lambda_sqr);
2805  const double b_lund =
2806  separate_fragment_hadron ? stringz_b_leading_ : stringz_b_produce_;
2807  /* The probability to flip sign of xpz_pos is taken from
2808  * StringFragmentation::finalTwo in StringFragmentation.cc
2809  * of PYTHIA 8. */
2810  const double prob_reverse =
2811  std::exp(-b_lund * lambda) / (1. + std::exp(-b_lund * lambda));
2812  double xpz_pos = 0.5 * lambda / mTsqr_string;
2813  if (random::uniform(0., 1.) < prob_reverse) {
2814  xpz_pos = -xpz_pos;
2815  }
2816 
2817  ppos_had_forward = (xe_pos + xpz_pos) * ppos_string;
2818  ppos_had_backward = (xe_neg - xpz_pos) * ppos_string;
2819 
2820  pneg_had_forward = 0.5 * mTsqr_had_forward / ppos_had_forward;
2821  pneg_had_backward = 0.5 * mTsqr_had_backward / ppos_had_backward;
2822 
2823  return true;
2824 }
double stringz_b_leading_
parameter (StringZ:bLund) for the fragmentation function of leading baryon in soft non-diffractive st...
constexpr T pow_int(const T base, unsigned const exponent)
Efficient template for calculating integer powers using squaring.
Definition: pow.h:23
double stringz_b_produce_
parameter (StringZ:bLund) for the fragmentation function of other (produced) hadrons in soft non-diff...
T uniform(T min, T max)
Definition: random.h:88

Here is the call graph for this function:

Here is the caller graph for this function:

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

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 2826 of file processstring.cc.

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

Here is the call graph for this function:

Here is the caller graph for this function:

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 2858 of file processstring.cc.

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

Here is the call graph for this function:

Here is the caller graph for this function:

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

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

y to factor_yrapid * y + diff_yrapid

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

Definition at line 1028 of file processstring.h.

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

Here is the call graph for this function:

Here is the caller graph for this function:

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 3177 of file processstring.cc.

3180  {
3181  // Set each particle's cross section scaling factor to 0 first
3182  for (ParticleData &data : outgoing_particles) {
3183  data.set_cross_section_scaling_factor(0.0);
3184  }
3185  // sort outgoing particles according to the longitudinal velocity
3186  std::sort(outgoing_particles.begin(), outgoing_particles.end(),
3187  [&](ParticleData i, ParticleData j) {
3188  return i.momentum().velocity() * evecLong >
3189  j.momentum().velocity() * evecLong;
3190  });
3191  int nq1, nq2; // number of quarks at both ends of the string
3192  switch (baryon_string) {
3193  case 0:
3194  nq1 = -1;
3195  nq2 = 1;
3196  break;
3197  case 1:
3198  nq1 = 2;
3199  nq2 = 1;
3200  break;
3201  case -1:
3202  nq1 = -2;
3203  nq2 = -1;
3204  break;
3205  default:
3206  throw std::runtime_error("string is neither mesonic nor baryonic");
3207  }
3208  // Try to find nq1 on one string end and nq2 on the other string end and the
3209  // other way around. When the leading particles are close to the string ends,
3210  // the quarks are assumed to be distributed this way.
3211  std::pair<int, int> i = find_leading(nq1, nq2, outgoing_particles);
3212  std::pair<int, int> j = find_leading(nq2, nq1, outgoing_particles);
3213  if (baryon_string == 0 && i.second - i.first < j.second - j.first) {
3214  assign_scaling_factor(nq2, outgoing_particles[j.first], suppression_factor);
3215  assign_scaling_factor(nq1, outgoing_particles[j.second],
3216  suppression_factor);
3217  } else {
3218  assign_scaling_factor(nq1, outgoing_particles[i.first], suppression_factor);
3219  assign_scaling_factor(nq2, outgoing_particles[i.second],
3220  suppression_factor);
3221  }
3222 }
static void assign_scaling_factor(int nquark, ParticleData &data, double suppression_factor)
Assign a cross section scaling factor to the given particle.
static std::pair< int, int > find_leading(int nq1, int nq2, ParticleList &list)
Find the leading string fragments.

Here is the call graph for this function:

Here is the caller graph for this function:

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 3160 of file processstring.cc.

3161  {
3162  assert(list.size() >= 2);
3163  int end = list.size() - 1;
3164  int i1, i2;
3165  for (i1 = 0;
3166  i1 <= end && !list[i1].pdgcode().contains_enough_valence_quarks(nq1);
3167  i1++) {
3168  }
3169  for (i2 = end;
3170  i2 >= 0 && !list[i2].pdgcode().contains_enough_valence_quarks(nq2);
3171  i2--) {
3172  }
3173  std::pair<int, int> indices(i1, i2);
3174  return indices;
3175 }

Here is the caller graph for this function:

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 3145 of file processstring.cc.

3146  {
3147  int nbaryon = data.pdgcode().baryon_number();
3148  if (nbaryon == 0) {
3149  // Mesons always get a scaling factor of 1/2 since there is never
3150  // a q-qbar pair at the end of a string so nquark is always 1
3151  data.set_cross_section_scaling_factor(0.5 * suppression_factor);
3152  } else if (data.is_baryon()) {
3153  // Leading baryons get a factor of 2/3 if they carry 2
3154  // and 1/3 if they carry 1 of the strings valence quarks
3155  data.set_cross_section_scaling_factor(suppression_factor * nquark /
3156  (3.0 * nbaryon));
3157  }
3158 }

Here is the call graph for this function:

Here is the caller graph for this function:

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 3224 of file processstring.cc.

3224  {
3225  PdgCode pdg_mapped(0x0);
3226 
3227  if (pdg.baryon_number() == 1) { // baryon
3228  pdg_mapped = pdg.charge() > 0 ? PdgCode(pdg::p) : PdgCode(pdg::n);
3229  } else if (pdg.baryon_number() == -1) { // antibaryon
3230  pdg_mapped = pdg.charge() < 0 ? PdgCode(-pdg::p) : PdgCode(-pdg::n);
3231  } else if (pdg.is_hadron()) { // meson
3232  if (pdg.charge() >= 0) {
3233  pdg_mapped = PdgCode(pdg::pi_p);
3234  } else {
3235  pdg_mapped = PdgCode(pdg::pi_m);
3236  }
3237  } else if (pdg.is_lepton()) { // lepton
3238  pdg_mapped = pdg.charge() < 0 ? PdgCode(0x11) : PdgCode(-0x11);
3239  } else {
3240  throw std::runtime_error("StringProcess::pdg_map_for_pythia failed.");
3241  }
3242 
3243  return pdg_mapped.get_decimal();
3244 }
constexpr int pi_p
π⁺.
constexpr int p
Proton.
constexpr int pi_m
π⁻.
constexpr int n
Neutron.

Here is the call graph for this function:

Here is the caller graph for this function:

Member Data Documentation

double smash::StringProcess::PPosA_
private

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

Definition at line 50 of file processstring.h.

double smash::StringProcess::PPosB_
private

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

Definition at line 52 of file processstring.h.

double smash::StringProcess::PNegA_
private

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

Definition at line 54 of file processstring.h.

double smash::StringProcess::PNegB_
private

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

Definition at line 56 of file processstring.h.

double smash::StringProcess::massA_
private

mass of incoming particle A [GeV]

Definition at line 58 of file processstring.h.

double smash::StringProcess::massB_
private

mass of incoming particle B [GeV]

Definition at line 60 of file processstring.h.

double smash::StringProcess::sqrtsAB_
private

sqrt of Mandelstam variable s of collision [GeV]

Definition at line 62 of file processstring.h.

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

PdgCodes of incoming particles.

Definition at line 64 of file processstring.h.

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

momenta of incoming particles in the lab frame [GeV]

Definition at line 66 of file processstring.h.

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

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

Definition at line 68 of file processstring.h.

FourVector smash::StringProcess::ucomAB_
private

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

Definition at line 70 of file processstring.h.

ThreeVector smash::StringProcess::vcomAB_
private

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

Definition at line 72 of file processstring.h.

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 77 of file processstring.h.

int smash::StringProcess::NpartFinal_
private

total number of final state particles

Definition at line 79 of file processstring.h.

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

number of particles fragmented from strings

Definition at line 81 of file processstring.h.

double smash::StringProcess::pmin_gluon_lightcone_
private

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

Definition at line 83 of file processstring.h.

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 88 of file processstring.h.

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 93 of file processstring.h.

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 98 of file processstring.h.

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 104 of file processstring.h.

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 109 of file processstring.h.

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 114 of file processstring.h.

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 119 of file processstring.h.

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 124 of file processstring.h.

double smash::StringProcess::kappa_tension_string_
private

string tension [GeV/fm]

Definition at line 126 of file processstring.h.

double smash::StringProcess::additional_xsec_supp_
private

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

Definition at line 131 of file processstring.h.

double smash::StringProcess::time_formation_const_
private

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

Definition at line 133 of file processstring.h.

double smash::StringProcess::soft_t_form_
private

factor to be multiplied to formation times in soft strings

Definition at line 135 of file processstring.h.

double smash::StringProcess::time_collision_
private

time of collision in the computational frame [fm]

Definition at line 137 of file processstring.h.

bool smash::StringProcess::mass_dependent_formation_times_
private

Whether the formation time should depend on the mass of the fragment according to Andersson:1983ia 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 149 of file processstring.h.

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 154 of file processstring.h.

bool smash::StringProcess::separate_fragment_baryon_
private

Whether to use a separate fragmentation function for leading baryons.

Definition at line 157 of file processstring.h.

bool smash::StringProcess::pythia_parton_initialized_ = false
private

Remembers if Pythia is initialized or not.

Definition at line 159 of file processstring.h.

ParticleList smash::StringProcess::final_state_
private

final state array which must be accessed after the collision

Definition at line 165 of file processstring.h.

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

PYTHIA object used in hard string routine.

Definition at line 168 of file processstring.h.

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

PYTHIA object used in fragmentation.

Definition at line 171 of file processstring.h.

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

An object to compute cross-sections.

Definition at line 174 of file processstring.h.

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 180 of file processstring.h.

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

event record for intermediate partonic state in the hard string routine

Definition at line 186 of file processstring.h.


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