Version: SMASH-3.4
smash::StringProcess Class Reference

#include <stringprocess.h>

String excitation processes used in SMASH.

Only one instance of this class should be created.

This class implements string excitation processes based on the UrQMD model Bass:1998ca [8], Bleicher:1999xi [13] and subsequent fragmentation according to the LUND/PYTHIA fragmentation scheme Andersson:1983ia [5], Sjostrand:2014zea [60], Bierlich:2022pfr [11].

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 stringprocess.h.

Collaboration diagram for smash::StringProcess:
[legend]

Public Types

enum class  LeadingStatus : int {
  LeadingQuark = 202 , LeadingDiquark = 63 , NonLeadingParton = 23 , FromLeadingQuark = 203 ,
  FromLeadingDiquark = 204
}
 PYTHIA status codes used to track leading/valence ancestry. More...
 

Public Member Functions

 StringProcess (Configuration &config)
 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...
 
void tag_leading_hadrons (Pythia8::Event &event)
 Tag leading hadrons in a hadronized string. More...
 
bool next (ProcessType type)
 Generate the next string process for a given process type. More...
 
bool string_above_threshold (const Pythia8::Event &event)
 Check whether all strings in a PYTHIA event are above fragmentation threshold. More...
 
double estimate_string_threshold (int p_left, int p_right)
 Estimate the minimum invariant mass required for a string to fragment. More...
 
void set_color_by_type (Pythia8::Particle &p, int color)
 Set the color or anticolor index of a particle according to its type. More...
 
std::optional< ParticleList > hadronize (const Pythia8::Event &string_evt)
 Hadronize a single partonic string configuration using Pythia8 and convert the produced hadrons into SMASH particles. 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 [56]. 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 form_intermediate_particles. More...
 
void set_mpi_initialization_sqrts (double sqrts)
 Set the center-of-mass energy used to initialize MPI-capable Pythia objects. 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...
 
void replace_constituent (Pythia8::Particle &particle, std::array< int, 5 > &excess_constituent)
 Convert a partonic PYTHIA particle into the desired species and update the excess of constituents. More...
 
void find_total_number_constituent (Pythia8::Event &event_intermediate, std::array< int, 5 > &nquark_total, std::array< int, 5 > &nantiq_total)
 Compute how many quarks and antiquarks we have in the system, and update the correspoing arrays with size 5. More...
 
bool splitting_gluon_qqbar (Pythia8::Event &event_intermediate, std::array< int, 5 > &nquark_total, std::array< int, 5 > &nantiq_total, bool sign_constituent, std::array< std::array< int, 5 >, 2 > &excess_constituent)
 Take total number of quarks and check if the system has enough constituents that need to be converted into other flavors. More...
 
void rearrange_excess (std::array< int, 5 > &nquark_total, std::array< std::array< int, 5 >, 2 > &excess_quark, std::array< std::array< int, 5 >, 2 > &excess_antiq)
 Take total number of quarks and check if the system has enough constituents that need to be converted into other flavors. More...
 
bool restore_constituent (Pythia8::Event &event_intermediate, std::array< std::array< int, 5 >, 2 > &excess_quark, std::array< std::array< int, 5 >, 2 > &excess_antiq)
 Take the intermediate partonic state from PYTHIA event with mapped hadrons and convert constituents into the desired ones according to the excess of quarks and anti-quarks. More...
 
void compose_string_parton (bool find_forward_string, Pythia8::Event &event_intermediate, Pythia8::Event &event_hadronize)
 Identify a set of partons, which are connected to form a color-neutral string, from a given PYTHIA event record. More...
 
void compose_string_junction (bool &find_forward_string, Pythia8::Event &event_intermediate, Pythia8::Event &event_hadronize)
 Identify a set of partons and junction(s), which are connected to form a color-neutral string, from a given PYTHIA event record. More...
 
void find_junction_leg (bool sign_color, std::vector< int > &col, Pythia8::Event &event_intermediate, Pythia8::Event &event_hadronize)
 Identify partons, which are associated with junction legs, from a given PYTHIA event record. More...
 
int get_index_forward (bool find_forward, int np_end, Pythia8::Event &event)
 Obtain index of the most forward or backward particle in a given PYTHIA event record. More...
 
void form_intermediate_particles (ParticleList &intermediate_particles, const FourVector &pString, const ThreeVector &evecLong, double additional_xsec_supp=1.0, bool find_and_scale_leading=true)
 Set formation times and cross-section scaling factors for fragmented hadrons as described in Andersson:1983ia [5]. More...
 
double getPPosA ()
 
double getPNegA ()
 
double getPPosB ()
 
double getPnegB ()
 
double get_massA ()
 
double get_massB ()
 
double get_sqrts ()
 
std::array< PdgCode, 2 > get_PDGs ()
 
std::array< FourVector, 2 > get_plab ()
 
std::array< FourVector, 2 > get_pcom ()
 
FourVector get_ucom ()
 
ThreeVector get_vcom ()
 
double get_tcoll ()
 
ParticleList get_final_state ()
 

Static Public Member Functions

static FourVector make_smash_4vec (const Pythia8::Vec4 &p)
 Convert a PYTHIA four-vector into a SMASH four-vector. More...
 
static Pythia8::Vec4 make_pythia_4vec (const FourVector &p)
 Convert a SMASH four-vector into a PYTHIA four-vector. More...
 
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 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...
 

Public Attributes

Pythia8::RotBstMatrix to_cm_
 Rotation/boost matrix to transform particles to the center-of-mass frame. More...
 

Private Types

typedef std::map< std::pair< int, int >, std::unique_ptr< Pythia8::Pythia > > pythia_map
 Map containing PYTHIA objects for hard string routines. More...
 

Private Member Functions

std::vector< bool > compute_beam_valence_flags (Pythia8::Pythia &pythia)
 Compute flags identifying beam valence partons (quarks or diquarks) that act as leading partons after the initial interaction. More...
 
int leading_hadron_status_from_endpoint (const Pythia8::Particle &end)
 Determine the custom leading-hadron status code from a string endpoint. More...
 
bool is_leading_parton (const Pythia8::Particle &p)
 Check whether a particle is tagged as a leading parton. More...
 
bool is_leading_from_quark (const Pythia8::Particle &p)
 Check whether a particle is tagged as originating from a leading quark. More...
 
bool is_leading_from_diquark (const Pythia8::Particle &p)
 Check whether a particle is tagged as originating from a leading diquark. More...
 
bool is_leading (const Pythia8::Particle &p)
 Check whether a particle is tagged as originating from a leading endpoint. More...
 
bool append_string (const Pythia8::Vec4 &p_str, const std::array< int, 2 > &ends, int color_tag, bool use_projectile_axis, bool random_flip_of_endpoints=false)
 Append a single two-endpoint string as an independent PYTHIA event. More...
 
bool next_SDiff (bool is_AB_to_AX)
 Single-diffractive process is based on single pomeron exchange described in Ingelman:1984ns [32]. 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 [8], Bleicher:1999xi [13]. More...
 
bool next_NDiffSoft ()
 Soft Non-diffractive process is modelled in accordance with dual-topological approach Capella:1978ig [18]. More...
 
bool next_Hard (ProcessType type)
 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 [8], Bleicher:1999xi [13] does, it create two mesonic strings after annihilating one quark-antiquark pair. 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...
 
double pmin_gluon_lightcone_
 the minimum lightcone momentum scale carried by a gluon [GeV] More...
 
double pow_fgluon_beta_
 parameter \(\beta\) for the gluon distribution function \( P(x) = x^{-1} (1 - x)^{1 + \beta} \) More...
 
double pow_fquark_alpha_
 parameter \(\alpha\) for the quark distribution function \( P(x) = x^{\alpha - 1} (1 - x)^{\beta - 1} \) More...
 
double pow_fquark_beta_
 parameter \(\beta\) for the quark distribution function \( P(x) = x^{\alpha - 1} (1 - x)^{\beta - 1} \) More...
 
double sigma_qperp_
 Transverse momentum spread of the excited strings. More...
 
double stringz_a_leading_
 parameter (StringZ:aLund) for the fragmentation function of leading baryon in soft non-diffractive string processes More...
 
double stringz_b_leading_
 parameter (StringZ:bLund) for the fragmentation function of leading baryon in soft non-diffractive string processes More...
 
double stringz_a_produce_
 parameter (StringZ:aLund) for the fragmentation function of other (produced) hadrons in soft non-diffractive string processes More...
 
double stringz_b_produce_
 parameter (StringZ:bLund) for the fragmentation function of other (produced) hadrons in soft non-diffractive string processes More...
 
double strange_supp_
 strange quark suppression factor More...
 
double diquark_supp_
 diquark suppression factor More...
 
double popcorn_rate_
 popcorn rate More...
 
double damp_popcorn_
 damp popcorn meson from diquark remnant endpoint rate More...
 
double string_sigma_T_
 transverse momentum spread in string fragmentation More...
 
double kappa_tension_string_
 string tension [GeV/fm] 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 [5] eq. More...
 
double prob_proton_to_d_uu_
 Probability of splitting a nucleon into the quark flavour it has only once and a diquark it has twice. More...
 
bool separate_fragment_baryon_
 Whether to use a separate fragmentation function for leading baryons. More...
 
bool use_monash_tune_
 Whether to use the monash tune Skands:2014pea [61] for all string processes. More...
 
double additional_xsec_supp_
 additional cross-section suppression factor to take coherence effect into account. More...
 
std::optional< double > mpi_initialization_sqrts_
 Optional center-of-mass energy used to initialize MPI-capable Pythia objects. More...
 
std::vector< std::string > pythia_settings_
 Additional Pythia 8 settings passed to each internal Pythia instance. More...
 
ParticleList final_state_
 final state array which must be accessed after the collision More...
 
pythia_map hard_map_
 Map object to contain the different pythia objects. More...
 
std::unique_ptr< Pythia8::Pythia > pythia_hadron_
 PYTHIA object used in fragmentation. More...
 
Pythia8::SigmaTotal pythia_sigmatot_
 An object to compute cross-sections. More...
 
Pythia8::StringFlav pythia_stringflav_
 An object for the flavor selection in string fragmentation in the case of separate fragmentation function for leading baryon. More...
 
Pythia8::Event event_intermediate_
 event record for intermediate partonic state in the hard string routine More...
 
std::vector< Pythia8::Event > string_parton_events_
 PYTHIA event records containing string partons to be hadronized. More...
 

Member Typedef Documentation

◆ pythia_map

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

Map containing PYTHIA objects for hard string routines.

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

Definition at line 288 of file stringprocess.h.

Member Enumeration Documentation

◆ LeadingStatus

PYTHIA status codes used to track leading/valence ancestry.

PYTHIA uses integer status codes to classify particles in the event record. SMASH uses a combination of standard PYTHIA codes and custom internal codes to tag leading partons and hadrons originating from leading quark/diquark endpoints.

Custom values are chosen to avoid collisions with commonly used PYTHIA internal codes. Standard PYTHIA values are used deliberately where they activate specific hadronization machinery.

Enumerator
LeadingQuark 

Custom status assigned to leading (valence) quarks.

LeadingDiquark 

Standard PYTHIA beam-remnant status used for leading diquarks.

Leading diquarks are assigned status 63 so that PYTHIA treats them
as beam remnants during hadronization. This allows PYTHIA's beam
remnant machinery to be used for leading baryon production, including
popcorn suppression and the optional hard-remnant-baryon treatment.

In particular, when BeamRemnants:hardRemnantBaryon is enabled,
PYTHIA replaces the standard Lund symmetric fragmentation function
for the leading baryon by a dedicated remnant-baryon fragmentation
function controlled by BeamRemnants:aRemnantBaryon and
BeamRemnants:bRemnantBaryon. This produces harder leading baryons
than ordinary string fragmentation.

Therefore status 63 is intentionally used here rather than a custom
status code. 
NonLeadingParton 

Standard PYTHIA status for non-leading partons that should be hadronized.

The PYTHIA manual recommends status 23 for particles provided as input to standalone hadronization. The precise value is not physically important here, but using the recommended status keeps the event record conventional.

See: https://pythia.org/latest-manual/HadronLevelStandalone.html

FromLeadingQuark 

Custom status assigned to hadrons containing a leading quark.

FromLeadingDiquark 

Custom status assigned to hadrons containing a leading diquark.

Definition at line 454 of file stringprocess.h.

454  : int {
455  /// Custom status assigned to leading (valence) quarks.
456  LeadingQuark = 202,
457 
458  /// Standard PYTHIA beam-remnant status used for leading diquarks.
459  ///
460  /// Leading diquarks are assigned status 63 so that PYTHIA treats them
461  /// as beam remnants during hadronization. This allows PYTHIA's beam
462  /// remnant machinery to be used for leading baryon production, including
463  /// popcorn suppression and the optional hard-remnant-baryon treatment.
464  ///
465  /// In particular, when BeamRemnants:hardRemnantBaryon is enabled,
466  /// PYTHIA replaces the standard Lund symmetric fragmentation function
467  /// for the leading baryon by a dedicated remnant-baryon fragmentation
468  /// function controlled by BeamRemnants:aRemnantBaryon and
469  /// BeamRemnants:bRemnantBaryon. This produces harder leading baryons
470  /// than ordinary string fragmentation.
471  ///
472  /// Therefore status 63 is intentionally used here rather than a custom
473  /// status code.
474  LeadingDiquark = 63,
475 
476  /// Standard PYTHIA status for non-leading partons that should be
477  /// hadronized.
478  ///
479  /// The PYTHIA manual recommends status 23 for particles provided as
480  /// input to standalone hadronization. The precise value is not
481  /// physically important here, but using the recommended status keeps
482  /// the event record conventional.
483  ///
484  /// See:
485  /// https://pythia.org/latest-manual/HadronLevelStandalone.html
486  NonLeadingParton = 23,
487 
488  /// Custom status assigned to hadrons containing a leading quark.
489  FromLeadingQuark = 203,
490 
491  /// Custom status assigned to hadrons containing a leading diquark.
492  FromLeadingDiquark = 204,
493  };

Constructor & Destructor Documentation

◆ StringProcess()

smash::StringProcess::StringProcess ( Configuration config)
explicit

Constructor, initializes PYTHIA.

Should only be called once.

All parameters are taken from config via Configuration::take.

Parameters
[in,out]configSMASH configuration object (keys are consumed)

Definition at line 29 of file stringprocess.cc.

68  // setup and initialize pythia for fragmentation
69  pythia_hadron_ = std::make_unique<Pythia8::Pythia>(PYTHIA_XML_DIR, false);
70  /* turn off all parton-level processes to implement only hadronization */
71  pythia_hadron_->readString("ProcessLevel:all = off");
75  pythia_hadron_->init();
76  /*
77  * The const_cast<type>() function is used to obtain the reference of the
78  * PrivateInfo object in the pythia_hadron_.
79  * This cast is needed since Pythia 8.302 which included a major architecture
80  * change. The Info object of a Pythia object is now private, only a const
81  * reference can be obtained.
82  * In order to reference the PrivateInfo object during initialization, we
83  * cast the const reference to obtain the stored address.
84  */
85  pythia_sigmatot_.initInfoPtr(
86  const_cast<Pythia8::Info&>(pythia_hadron_->info));
87  pythia_sigmatot_.init();
88 
89  pythia_stringflav_.initInfoPtr(
90  const_cast<Pythia8::Info&>(pythia_hadron_->info));
91  pythia_stringflav_.init();
92 
93  event_intermediate_.init("intermediate partons",
94  &pythia_hadron_->particleData);
95 
96  for (int imu = 0; imu < 3; imu++) {
97  evecBasisAB_[imu] = ThreeVector(0., 0., 0.);
98  }
99 
100  final_state_.clear();
101 }
Pythia8::StringFlav pythia_stringflav_
An object for the flavor selection in string fragmentation in the case of separate fragmentation func...
Pythia8::SigmaTotal pythia_sigmatot_
An object to compute cross-sections.
double pow_fgluon_beta_
parameter for the gluon distribution function
Definition: stringprocess.h:88
Pythia8::Event event_intermediate_
event record for intermediate partonic state in the hard string routine
double time_formation_const_
constant proper time in the case of constant formation time [fm]
double pow_fquark_beta_
parameter for the quark distribution function
Definition: stringprocess.h:98
double prob_proton_to_d_uu_
Probability of splitting a nucleon into the quark flavour it has only once and a diquark it has twice...
double popcorn_rate_
popcorn rate
double pmin_gluon_lightcone_
the minimum lightcone momentum scale carried by a gluon [GeV]
Definition: stringprocess.h:83
ParticleList final_state_
final state array which must be accessed after the collision
bool use_monash_tune_
Whether to use the monash tune Skands:2014pea for all string processes.
double soft_t_form_
factor to be multiplied to formation times in soft strings
std::unique_ptr< Pythia8::Pythia > pythia_hadron_
PYTHIA object used in fragmentation.
void common_setup_pythia(Pythia8::Pythia *pythia_in, double strange_supp, double diquark_supp, double popcorn_rate, double stringz_a, double stringz_b, double string_sigma_T)
Common setup of PYTHIA objects for soft and hard string routines.
std::array< ThreeVector, 3 > evecBasisAB_
Orthonormal basis vectors in the center of mass frame, where the 0th one is parallel to momentum of i...
Definition: stringprocess.h:81
std::vector< std::string > pythia_settings_
Additional Pythia 8 settings passed to each internal Pythia instance.
double string_sigma_T_
transverse momentum spread in string fragmentation
double additional_xsec_supp_
additional cross-section suppression factor to take coherence effect into account.
double damp_popcorn_
damp popcorn meson from diquark remnant endpoint rate
double strange_supp_
strange quark suppression factor
double kappa_tension_string_
string tension [GeV/fm]
double pow_fquark_alpha_
parameter for the quark distribution function
Definition: stringprocess.h:93
double stringz_b_leading_
parameter (StringZ:bLund) for the fragmentation function of leading baryon in soft non-diffractive st...
bool mass_dependent_formation_times_
Whether the formation time should depend on the mass of the fragment according to Andersson:1983ia e...
double stringz_b_produce_
parameter (StringZ:bLund) for the fragmentation function of other (produced) hadrons in soft non-diff...
double stringz_a_leading_
parameter (StringZ:aLund) for the fragmentation function of leading baryon in soft non-diffractive st...
double sigma_qperp_
Transverse momentum spread of the excited strings.
bool separate_fragment_baryon_
Whether to use a separate fragmentation function for leading baryons.
double diquark_supp_
diquark suppression factor
double stringz_a_produce_
parameter (StringZ:aLund) for the fragmentation function of other (produced) hadrons in soft non-diff...
static const Key< double > collTerm_stringParam_probabilityPToDUU
See user guide description for more information.
Definition: input_keys.h:3622
static const Key< double > collTerm_stringParam_formationTime
See user guide description for more information.
Definition: input_keys.h:3453
static const Key< bool > collTerm_stringParam_useMonashTune
See user guide description for more information.
Definition: input_keys.h:3818
static const Key< double > collTerm_stringParam_sigmaPerp
See user guide description for more information.
Definition: input_keys.h:3660
static const Key< double > collTerm_stringParam_gluonPMin
See user guide description for more information.
Definition: input_keys.h:3486
static const Key< double > collTerm_stringParam_stringZALeading
See user guide description for more information.
Definition: input_keys.h:3759
static const Key< std::vector< std::string > > collTerm_stringParam_pythiaSettings
See user guide description for more information.
Definition: input_keys.h:3886
static const Key< double > collTerm_stringParam_unformedXsecSuppression
See user guide description for more information.
Definition: input_keys.h:3847
static const Key< bool > collTerm_stringParam_mDependentFormationTimes
See user guide description for more information.
Definition: input_keys.h:3504
static const Key< double > collTerm_stringParam_diquarkSuppression
See user guide description for more information.
Definition: input_keys.h:3419
static const Key< double > collTerm_stringParam_formTimeFactor
See user guide description for more information.
Definition: input_keys.h:3438
static const Key< double > collTerm_stringParam_quarkAlpha
See user guide description for more information.
Definition: input_keys.h:3520
static const Key< double > collTerm_stringParam_stringZA
See user guide description for more information.
Definition: input_keys.h:3739
static const Key< double > collTerm_stringParam_strangeSuppression
See user guide description for more information.
Definition: input_keys.h:3682
static const Key< double > collTerm_stringParam_stringSigmaT
See user guide description for more information.
Definition: input_keys.h:3701
static const Key< double > collTerm_stringParam_stringZB
See user guide description for more information.
Definition: input_keys.h:3778
static const Key< double > collTerm_stringParam_quarkBeta
See user guide description for more information.
Definition: input_keys.h:3536
static const Key< double > collTerm_stringParam_popcornRate
See user guide description for more information.
Definition: input_keys.h:3555
static const Key< double > collTerm_stringParam_stringZBLeading
See user guide description for more information.
Definition: input_keys.h:3799
static const Key< double > collTerm_stringParam_stringTension
See user guide description for more information.
Definition: input_keys.h:3722
static const Key< double > collTerm_stringParam_gluonBeta
See user guide description for more information.
Definition: input_keys.h:3469
static const Key< bool > collTerm_stringParam_separateFragmentBaryon
See user guide description for more information.
Definition: input_keys.h:3639
static const Key< double > collTerm_stringParam_dampPopcorn
See user guide description for more information.
Definition: input_keys.h:3582
Here is the call graph for this function:

Member Function Documentation

◆ compute_beam_valence_flags()

std::vector< bool > smash::StringProcess::compute_beam_valence_flags ( Pythia8::Pythia &  pythia)
private

Compute flags identifying beam valence partons (quarks or diquarks) that act as leading partons after the initial interaction.

The returned vector is aligned with the current Pythia event record (pythia.event): each entry is true if the corresponding particle is a valence parton originating from one of the incoming beam particles, i.e. a quark or diquark that carries the beam quantum numbers and should be considered "leading".

This typically includes valence quarks extracted during the initial scattering, as well as surviving diquark remnants of the beam.

Note
The size of the returned vector equals pythia.event.size().
Parameters
[in,out]pythiaPythia instance containing the event to inspect.
Returns
Per-particle flags for beam valence (leading) partons.

Definition at line 775 of file stringprocess.cc.

776  {
777  const Pythia8::Event& event = pythia.event;
778 
779  auto find_final_copy = [&](int iPos) -> int {
780  if (iPos <= 0 || iPos >= event.size())
781  return -1;
782  if (event[iPos].isFinal())
783  return iPos;
784 
785  const int id = event[iPos].id();
786  const auto ds = event[iPos].daughterListRecursive();
787  for (int j : ds) {
788  if (j > 0 && j < event.size() && event[j].isFinal() &&
789  event[j].id() == id)
790  return j;
791  }
792  return -1;
793  };
794 
795  auto tag_from_beam = [&](const Pythia8::BeamParticle& beam,
796  std::vector<bool>& isValenceFinal) -> void {
797  for (int i = 0; i < beam.size(); ++i) {
798  if (!beam[i].isValence()) {
799  continue;
800  }
801 
802  const int j = find_final_copy(beam[i].iPos());
803 
804  if (j >= 0 && (event[j].isQuark() || event[j].isDiquark())) {
805  isValenceFinal[j] = true;
806  }
807  }
808  };
809  auto tag_from_unresolved_diff_systems =
810  [&](std::vector<bool>& isValenceFinal) -> void {
811  for (int i = 1; i < event.size(); ++i) {
812  if (event[i].statusAbs() != 15) {
813  continue;
814  }
815 
816  std::vector<int> endpoint_daughters;
817  bool resolved_system = false;
818 
819  for (int d : event[i].daughterList()) {
820  if (d <= 0 || d >= event.size()) {
821  continue;
822  }
823 
824  if (event[d].isQuark() || event[d].isDiquark()) {
825  endpoint_daughters.push_back(d);
826  continue;
827  }
828 
829  if (!event[d].isGluon()) {
830  resolved_system = true;
831  }
832  }
833 
834  if (resolved_system || endpoint_daughters.empty()) {
835  continue;
836  }
837 
838  bool already_tagged = false;
839  for (int j : endpoint_daughters) {
840  if (isValenceFinal[j]) {
841  already_tagged = true;
842  break;
843  }
844  }
845 
846  if (already_tagged) {
847  continue;
848  }
849 
850  for (int j : endpoint_daughters) {
851  isValenceFinal[j] = true;
852  }
853  }
854  };
855 
856  std::vector<bool> isValenceFinal(event.size(), false);
857  tag_from_beam(pythia.beamA, isValenceFinal);
858  tag_from_beam(pythia.beamB, isValenceFinal);
859 
860  tag_from_unresolved_diff_systems(isValenceFinal);
861 
862  return isValenceFinal;
863 }
Here is the caller graph for this function:

◆ leading_hadron_status_from_endpoint()

int smash::StringProcess::leading_hadron_status_from_endpoint ( const Pythia8::Particle &  end)
inlineprivate

Determine the custom leading-hadron status code from a string endpoint.

For a string endpoint particle, return the appropriate SMASH leading status: diquark endpoints map to FROM_Leading_Diquark, otherwise FROM_Leading_Quark.

Parameters
[in]endString endpoint particle (quark or diquark).
Returns
Integer status code corresponding to the appropriate LeadingStatus.

Definition at line 222 of file stringprocess.h.

222  {
223  return static_cast<int>(end.isDiquark() ? LeadingStatus::FromLeadingDiquark
225  }
@ FromLeadingDiquark
Custom status assigned to hadrons containing a leading diquark.
@ FromLeadingQuark
Custom status assigned to hadrons containing a leading quark.
Here is the caller graph for this function:

◆ is_leading_parton()

bool smash::StringProcess::is_leading_parton ( const Pythia8::Particle &  p)
inlineprivate

Check whether a particle is tagged as a leading parton.

Parameters
[in]pPythia particle.
Returns
True if p has statusAbs() equal to LeadingStatus::Leading_Quark or LeadingStatus::Leading_Diquark.

Definition at line 234 of file stringprocess.h.

234  {
235  return p.statusAbs() == static_cast<int>(LeadingStatus::LeadingQuark) ||
236  p.statusAbs() == static_cast<int>(LeadingStatus::LeadingDiquark);
237  }
@ LeadingQuark
Custom status assigned to leading (valence) quarks.
@ LeadingDiquark
Standard PYTHIA beam-remnant status used for leading diquarks.
constexpr int p
Proton.
Here is the caller graph for this function:

◆ is_leading_from_quark()

bool smash::StringProcess::is_leading_from_quark ( const Pythia8::Particle &  p)
inlineprivate

Check whether a particle is tagged as originating from a leading quark.

Parameters
[in]pPythia particle.
Returns
True if p has statusAbs() equal to LeadingStatus::FROM_Leading_Quark.

Definition at line 246 of file stringprocess.h.

246  {
247  return p.statusAbs() == static_cast<int>(LeadingStatus::FromLeadingQuark);
248  }
Here is the caller graph for this function:

◆ is_leading_from_diquark()

bool smash::StringProcess::is_leading_from_diquark ( const Pythia8::Particle &  p)
inlineprivate

Check whether a particle is tagged as originating from a leading diquark.

Parameters
[in]pPythia particle.
Returns
True if p has statusAbs() equal to LeadingStatus::FROM_Leading_Diquark.

Definition at line 257 of file stringprocess.h.

257  {
258  return p.statusAbs() == static_cast<int>(LeadingStatus::FromLeadingDiquark);
259  }
Here is the caller graph for this function:

◆ is_leading()

bool smash::StringProcess::is_leading ( const Pythia8::Particle &  p)
inlineprivate

Check whether a particle is tagged as originating from a leading endpoint.

This is the union of is_leading_from_quark() and is_leading_from_diquark().

Parameters
[in]pPythia particle.
Returns
True if p is tagged as leading-from-quark or leading-from-diquark.

Definition at line 272 of file stringprocess.h.

272  {
274  }
bool is_leading_from_quark(const Pythia8::Particle &p)
Check whether a particle is tagged as originating from a leading quark.
bool is_leading_from_diquark(const Pythia8::Particle &p)
Check whether a particle is tagged as originating from a leading diquark.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ append_string()

bool smash::StringProcess::append_string ( const Pythia8::Vec4 &  p_str,
const std::array< int, 2 > &  ends,
int  color_tag,
bool  use_projectile_axis,
bool  random_flip_of_endpoints = false 
)
private

Append a single two-endpoint string as an independent PYTHIA event.

A minimal partonic event is constructed containing a string with the specified endpoint flavors and total four-momentum. The endpoint momenta are determined from two-body kinematics in the string rest frame and are aligned with either the projectile or target beam direction before being boosted back to the collision frame.

Strings whose invariant mass is below the estimated fragmentation threshold are rejected.

Parameters
[in]p_strFour-momentum of the string.
[in]endsPDG ids of the two string endpoints.
[in]color_tagColor tag used to connect the string endpoints.
[in]use_projectile_axisWhether to align the string with the projectile beam direction. If false, the target beam direction is used.
[in]random_flip_of_endpointsWhether to randomly reverse the order of the two string endpoints before assigning endpoint momenta.
Returns
True if a valid string event was created and appended, false otherwise.

Definition at line 433 of file stringprocess.cc.

436  {
437  const bool flip_endpoints =
438  random_flip_of_endpoints && random::canonical() > 0.5;
439 
440  const int id1 = flip_endpoints ? ends[1] : ends[0];
441  const int id2 = flip_endpoints ? ends[0] : ends[1];
442  const auto& pd = pythia_hadron_->particleData;
443 
444  const double m_string = p_str.mCalc();
445 
446  if (m_string < estimate_string_threshold(id1, id2))
447  return false;
448 
449  const double m1 = pd.m0(id1);
450  const double m2 = pd.m0(id2);
451 
452  const double p_cm = pCM(m_string, m1, m2);
453  if (p_cm < really_small)
454  return false;
455 
456  const double E1 = std::sqrt(p_cm * p_cm + m1 * m1);
457  const double E2 = std::sqrt(p_cm * p_cm + m2 * m2);
458 
459  const int ibeam = use_projectile_axis ? 0 : 1;
460 
461  const ThreeVector mom = pcom_[ibeam].threevec();
462  Pythia8::Vec4 beam_axis_cm(mom.x1(), mom.x2(), mom.x3(), mom.abs());
463 
464  Pythia8::RotBstMatrix to_string_rest;
465  to_string_rest.bstback(p_str);
466 
467  Pythia8::Vec4 beam_axis_rest = to_string_rest * beam_axis_cm;
468 
469  const double norm = std::sqrt(beam_axis_rest.px() * beam_axis_rest.px() +
470  beam_axis_rest.py() * beam_axis_rest.py() +
471  beam_axis_rest.pz() * beam_axis_rest.pz());
472 
473  if (norm < really_small)
474  return false;
475 
476  const double nx = beam_axis_rest.px() / norm;
477  const double ny = beam_axis_rest.py() / norm;
478  const double nz = beam_axis_rest.pz() / norm;
479 
480  const Pythia8::Vec4 p1_rest(nx * p_cm, ny * p_cm, nz * p_cm, E1);
481  const Pythia8::Vec4 p2_rest(-nx * p_cm, -ny * p_cm, -nz * p_cm, E2);
482 
483  Pythia8::RotBstMatrix boost;
484  boost.bst(p_str);
485 
486  const Pythia8::Vec4 p1_cm = boost * p1_rest;
487  const Pythia8::Vec4 p2_cm = boost * p2_rest;
488 
489  // Create event for this string.
490  string_parton_events_.emplace_back();
491  Pythia8::Event& evt = string_parton_events_.back();
492  evt.init("Soft SMASH string", &pythia_hadron_->particleData);
493 
494  evt.append(90, -11, 0, 0, p1_cm + p2_cm, (p1_cm + p2_cm).mCalc());
495 
496  const int status_quark = static_cast<int>(LeadingStatus::LeadingQuark);
497  const int status_diquark = static_cast<int>(LeadingStatus::LeadingDiquark);
498 
499  const bool id1_is_quark = pythia_hadron_->particleData.isQuark(id1);
500  const bool id2_is_quark = pythia_hadron_->particleData.isQuark(id2);
501 
502  const int i1 = evt.append(id1, id1_is_quark ? status_quark : status_diquark,
503  0, 0, p1_cm, m1);
504  const int i2 = evt.append(id2, id2_is_quark ? status_quark : status_diquark,
505  0, 0, p2_cm, m2);
506 
507  set_color_by_type(evt[i1], color_tag);
508  set_color_by_type(evt[i2], color_tag);
509  evt.rotbst(to_cm_.inverse());
510  return true;
511 }
std::vector< Pythia8::Event > string_parton_events_
PYTHIA event records containing string partons to be hadronized.
Pythia8::RotBstMatrix to_cm_
Rotation/boost matrix to transform particles to the center-of-mass frame.
void set_color_by_type(Pythia8::Particle &p, int color)
Set the color or anticolor index of a particle according to its type.
std::array< FourVector, 2 > pcom_
momenta of incoming particles in the center of mass frame [GeV]
Definition: stringprocess.h:72
double estimate_string_threshold(int p_left, int p_right)
Estimate the minimum invariant mass required for a string to fragment.
T canonical()
Definition: random.h:122
T pCM(const T sqrts, const T mass_a, const T mass_b) noexcept
Definition: kinematics.h:79
constexpr double really_small
Numerical error tolerance.
Definition: constants.h:41
Here is the call graph for this function:
Here is the caller graph for this function:

◆ next_SDiff()

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

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

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

513  {
514  double massH = is_AB_to_AX ? massA_ : massB_;
515  double mstrMin = is_AB_to_AX ? massB_ : massA_;
516  double mstrMax = sqrtsAB_ - massH;
517 
518  int idqX1, idqX2;
519  double QTrn, QTrx, QTry;
520  double pabscomHX_sqr, massX;
521 
522  // decompose hadron into quarks
523  make_string_ends(is_AB_to_AX ? PDGcodes_[1] : PDGcodes_[0], idqX1, idqX2,
525  // string mass must be larger than threshold set by PYTHIA.
526  mstrMin = pythia_hadron_->particleData.m0(idqX1) +
527  pythia_hadron_->particleData.m0(idqX2);
528  // this threshold cannot be larger than maximum of allowed string mass.
529  if (mstrMin > mstrMax) {
530  return false;
531  }
532  // sample the transverse momentum transfer
533  QTrx = random::normal(0., sigma_qperp_ * M_SQRT1_2);
534  QTry = random::normal(0., sigma_qperp_ * M_SQRT1_2);
535  QTrn = std::sqrt(QTrx * QTrx + QTry * QTry);
536  /* sample the string mass and
537  * evaluate the three-momenta of hadron and string. */
538  massX = random::power(-1.0, mstrMin, mstrMax);
539  pabscomHX_sqr = pCM_sqr(sqrtsAB_, massH, massX);
540  /* magnitude of the three momentum must be larger
541  * than the transverse momentum. */
542  const bool foundPabsX = pabscomHX_sqr > QTrn * QTrn;
543 
544  if (!foundPabsX) {
545  return false;
546  }
547 
548  // determine three momentum of the final state hadron
549  double sign_direction = is_AB_to_AX ? 1. : -1.;
550 
551  // longitudinal component (along +z by convention)
552  const double pL = std::sqrt(pabscomHX_sqr - QTrn * QTrn);
553 
554  // momentum of the outgoing hadron H in the CM frame
555  const ThreeVector cm_momentum(sign_direction * QTrx, sign_direction * QTry,
556  sign_direction * pL);
557 
558  const FourVector pstrHcom(std::sqrt(pabscomHX_sqr + massH * massH),
559  cm_momentum);
560  const FourVector pstrXcom(std::sqrt(pabscomHX_sqr + massX * massX),
561  -cm_momentum);
562 
563  if (!append_string(make_pythia_4vec(pstrXcom), {idqX2, idqX1}, 101,
564  !is_AB_to_AX)) {
565  return false;
566  }
567  PdgCode hadron_code = is_AB_to_AX ? PDGcodes_[0] : PDGcodes_[1];
568  ParticleData new_particle(ParticleType::find(hadron_code));
569 
570  auto had_mom = make_pythia_4vec(pstrHcom);
571  had_mom.rotbst(to_cm_.inverse());
572 
573  new_particle.set_4momentum(make_smash_4vec(had_mom));
574  new_particle.set_cross_section_scaling_factor(1.);
575  new_particle.set_formation_time(time_collision_);
576  final_state_.push_back(new_particle);
577 
578  return true;
579 }
static const ParticleType & find(PdgCode pdgcode)
Returns the ParticleType object for the given pdgcode.
Definition: particletype.cc:99
std::array< PdgCode, 2 > PDGcodes_
PdgCodes of incoming particles.
Definition: stringprocess.h:68
static FourVector make_smash_4vec(const Pythia8::Vec4 &p)
Convert a PYTHIA four-vector into a SMASH four-vector.
double sqrtsAB_
sqrt of Mandelstam variable s of collision [GeV]
Definition: stringprocess.h:66
bool append_string(const Pythia8::Vec4 &p_str, const std::array< int, 2 > &ends, int color_tag, bool use_projectile_axis, bool random_flip_of_endpoints=false)
Append a single two-endpoint string as an independent PYTHIA event.
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.
double massA_
mass of incoming particle A [GeV]
Definition: stringprocess.h:62
static Pythia8::Vec4 make_pythia_4vec(const FourVector &p)
Convert a SMASH four-vector into a PYTHIA four-vector.
double time_collision_
time of collision in the computational frame [fm]
double massB_
mass of incoming particle B [GeV]
Definition: stringprocess.h:64
T power(T n, T xMin, T xMax)
Sample from a power-law probability density proportional to |x|^n.
Definition: random.h:229
double normal(const T &mean, const T &sigma)
Returns a random number drawn from a normal distribution.
Definition: random.h:294
T pCM_sqr(const T sqrts, const T mass_a, const T mass_b) noexcept
Definition: kinematics.h:91
Here is the call graph for this function:
Here is the caller graph for this function:

◆ next_DDiff()

bool smash::StringProcess::next_DDiff ( )
private

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

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

Returns
whether the process is successfully implemented.

Definition at line 581 of file stringprocess.cc.

581  {
582  std::array<std::array<int, 2>, 2> quarks;
583 
584  // decompose hadron into quark (and diquark) contents
585  make_string_ends(PDGcodes_[0], quarks[0][1], quarks[0][0],
587  make_string_ends(PDGcodes_[1], quarks[1][1], quarks[1][0],
589  // sample the lightcone momentum fraction carried by gluons
590  const double xmin_gluon_fraction = pmin_gluon_lightcone_ / sqrtsAB_;
591  const double xfracA =
592  random::beta_a0(xmin_gluon_fraction, pow_fgluon_beta_ + 1.);
593  const double xfracB =
594  random::beta_a0(xmin_gluon_fraction, pow_fgluon_beta_ + 1.);
595  // sample the transverse momentum transfer
596  const double QTrx = random::normal(0., sigma_qperp_ * M_SQRT1_2);
597  const double QTry = random::normal(0., sigma_qperp_ * M_SQRT1_2);
598  const double QTrn = std::sqrt(QTrx * QTrx + QTry * QTry);
599  // evaluate the lightcone momentum transfer
600  const double QPos = -QTrn * QTrn / (2. * xfracB * PNegB_);
601  const double QNeg = QTrn * QTrn / (2. * xfracA * PPosA_);
602 
603  const double pz1 = ((PPosA_ + QPos) - (PNegA_ + QNeg)) * M_SQRT1_2;
604  const double E1 = ((PPosA_ + QPos) + (PNegA_ + QNeg)) * M_SQRT1_2;
605  Pythia8::Vec4 p_str1(QTrx, QTry, pz1, E1);
606 
607  const double pz2 = ((PPosB_ - QPos) - (PNegB_ - QNeg)) * M_SQRT1_2;
608  const double E2 = ((PPosB_ - QPos) + (PNegB_ - QNeg)) * M_SQRT1_2;
609  Pythia8::Vec4 p_str2(-QTrx, -QTry, pz2, E2);
610  if (random::uniform_int(0, 1) == 0) {
611  std::swap(quarks[0][0], quarks[0][1]);
612  }
613  if (random::uniform_int(0, 1) == 0) {
614  std::swap(quarks[1][0], quarks[1][1]);
615  }
616  return append_string(p_str1, quarks[0], 101, true) &&
617  append_string(p_str2, quarks[1], 102, false);
618 }
double PNegB_
backward lightcone momentum p^{-} of incoming particle B in CM-frame [GeV]
Definition: stringprocess.h:60
double PPosA_
forward lightcone momentum p^{+} of incoming particle A in CM-frame [GeV]
Definition: stringprocess.h:51
double PNegA_
backward lightcone momentum p^{-} of incoming particle A in CM-frame [GeV]
Definition: stringprocess.h:57
double PPosB_
forward lightcone momentum p^{+} of incoming particle B in CM-frame [GeV]
Definition: stringprocess.h:54
T beta_a0(T xmin, T b)
Draws a random number from a beta-distribution with a = 0.
Definition: random.h:395
T uniform_int(T min, T max)
Definition: random.h:106
Here is the call graph for this function:
Here is the caller graph for this function:

◆ next_NDiffSoft()

bool smash::StringProcess::next_NDiffSoft ( )
private

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

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

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

Definition at line 715 of file stringprocess.cc.

715  {
716  // ids of the two ends of each string
717  std::array<int, 2> endsA; // string built with p_strA
718  std::array<int, 2> endsB; // string built with p_strB
719 
720  // decompose hadron into quark (and diquark) contents
721  int idqA1, idqA2, idqB1, idqB2;
724 
725  const int bar_a = PDGcodes_[0].baryon_number();
726  const int bar_b = PDGcodes_[1].baryon_number();
727 
728  if (bar_a == 1 || // baryon-*
729  (bar_a == 0 && bar_b == 1) || // meson-baryon
730  (bar_a == 0 && bar_b == 0)) { // meson-meson
731  endsA = {idqA2, idqB1};
732  endsB = {idqB2, idqA1};
733  } else if ((bar_a == 0 && bar_b == -1) || // meson-antibaryon
734  (bar_a == -1)) { // antibaryon-*
735  endsA = {idqB2, idqA1};
736  endsB = {idqA2, idqB1};
737  } else {
738  std::stringstream ss;
739  ss << "StringProcess::next_NDiffSoft: baryonA = " << bar_a
740  << ", baryonB = " << bar_b;
741  throw std::runtime_error(ss.str());
742  }
743 
744  // CM frame with A along +z and B along -z; PPos/PNeg are lightcone components
745  // in this frame.
746 
747  // sample the lightcone momentum fraction carried by quarks
748  const double xfracA = random::beta(pow_fquark_alpha_, pow_fquark_beta_);
749  const double xfracB = random::beta(pow_fquark_alpha_, pow_fquark_beta_);
750 
751  // sample the transverse momentum transfer
752  const double qx = random::normal(0., sigma_qperp_ * M_SQRT1_2);
753  const double qy = random::normal(0., sigma_qperp_ * M_SQRT1_2);
754  const double qT2 = qx * qx + qy * qy;
755 
756  // evaluate the lightcone momentum transfer
757  const double QPos = -qT2 / (2. * xfracB * PNegB_);
758  const double QNeg = qT2 / (2. * xfracA * PPosA_);
759  const double dPPos = -xfracA * PPosA_ - QPos;
760  const double dPNeg = xfracB * PNegB_ - QNeg;
761 
762  // string from hadron A side (with +qT)
763  const double pzA = ((PPosA_ + dPPos) - (PNegA_ + dPNeg)) * M_SQRT1_2;
764  const double EA = ((PPosA_ + dPPos) + (PNegA_ + dPNeg)) * M_SQRT1_2;
765  Pythia8::Vec4 p_strA(qx, qy, pzA, EA);
766 
767  // string from hadron B side (with -qT)
768  const double pzB = ((PPosB_ - dPPos) - (PNegB_ - dPNeg)) * M_SQRT1_2;
769  const double EB = ((PPosB_ - dPPos) + (PNegB_ - dPNeg)) * M_SQRT1_2;
770  Pythia8::Vec4 p_strB(-qx, -qy, pzB, EB);
771  return append_string(p_strA, endsA, 101, true) &&
772  append_string(p_strB, endsB, 102, false);
773 }
T beta(T a, T b)
Draws a random number from a beta-distribution, where probability density of is .
Definition: random.h:373
Here is the call graph for this function:
Here is the caller graph for this function:

◆ next_Hard()

bool smash::StringProcess::next_Hard ( ProcessType  type)
private

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

Returns
whether the process is successfully implemented.

Definition at line 993 of file stringprocess.cc.

993  {
994  logg[LPythia].debug("Hard non-diff. with ", PDGcodes_[0], " + ", PDGcodes_[1],
995  " at CM energy [GeV] ", sqrtsAB_);
996 
997  std::array<int, 2> pdg_for_pythia;
998  std::array<std::array<int, 5>, 2> excess_quark;
999  std::array<std::array<int, 5>, 2> excess_antiq;
1000  for (int i = 0; i < 2; i++) {
1001  for (int j = 0; j < 5; j++) {
1002  excess_quark[i][j] = 0;
1003  excess_antiq[i][j] = 0;
1004  }
1005 
1006  // get PDG id used in PYTHIA event generation
1007  pdg_for_pythia[i] = pdg_map_for_pythia(PDGcodes_[i]);
1008  logg[LPythia].debug(" incoming particle ", i, " : ", PDGcodes_[i],
1009  " is mapped onto ", pdg_for_pythia[i]);
1010 
1011  PdgCode pdgcode_for_pythia(std::to_string(pdg_for_pythia[i]));
1012  /* evaluate how many more constituents incoming hadron has
1013  * compared to the mapped one. */
1014  find_excess_constituent(PDGcodes_[i], pdgcode_for_pythia, excess_quark[i],
1015  excess_antiq[i]);
1016  logg[LPythia].debug(" excess_quark[", i, "] = (", excess_quark[i][0],
1017  ", ", excess_quark[i][1], ", ", excess_quark[i][2],
1018  ", ", excess_quark[i][3], ", ", excess_quark[i][4],
1019  ")");
1020  logg[LPythia].debug(" excess_antiq[", i, "] = (", excess_antiq[i][0],
1021  ", ", excess_antiq[i][1], ", ", excess_antiq[i][2],
1022  ", ", excess_antiq[i][3], ", ", excess_antiq[i][4],
1023  ")");
1024  }
1025 
1026  std::pair<int, int> idAB{pdg_for_pythia[0], pdg_for_pythia[1]};
1027 
1028  // If an entry for the calculated particle IDs does not exist, create one
1029  // and initialize it accordingly
1030  if (hard_map_.count(idAB) == 0) {
1031  hard_map_[idAB] = std::make_unique<Pythia8::Pythia>(PYTHIA_XML_DIR, false);
1032  hard_map_[idAB]->readString("SoftQCD:nonDiffractive = on");
1033  hard_map_[idAB]->readString("SoftQCD:singleDiffractiveXB = on");
1034  hard_map_[idAB]->readString("SoftQCD:singleDiffractiveAX = on");
1035  hard_map_[idAB]->readString("SoftQCD:doubleDiffractive = on");
1036  hard_map_[idAB]->readString("HadronLevel:all = off");
1039  string_sigma_T_);
1040  hard_map_[idAB]->settings.flag("Beams:allowVariableEnergy", true);
1041  hard_map_[idAB]->settings.mode("Beams:idA", idAB.first);
1042  hard_map_[idAB]->settings.mode("Beams:idB", idAB.second);
1043  hard_map_[idAB]->settings.parm(
1044  "Beams:eCM", mpi_initialization_sqrts_.value_or(sqrtsAB_));
1045  logg[LPythia].debug("Pythia object initialized with ", pdg_for_pythia[0],
1046  " + ", pdg_for_pythia[1], " at CM energy [GeV] ",
1048  if (!hard_map_[idAB]->init()) {
1049  throw std::runtime_error("Pythia failed to initialize.");
1050  }
1051  }
1052  const int seed_new = random::uniform_int(1, maximum_rndm_seed_in_pythia);
1053  hard_map_[idAB]->rndm.init(seed_new);
1054  logg[LPythia].debug("hard_map_[", idAB.first, "][", idAB.second,
1055  "] : rndm is initialized with seed ", seed_new);
1056 
1057  // Change the energy using the Pythia 8.302+ feature
1058  hard_map_[idAB]->setKinematics(sqrtsAB_);
1059 
1060  bool final_state_success = false;
1061  /* Hard-process codes follow the Pythia convention:
1062  * https://www.pythia.org/latest-manual/QCDSoftProcesses.html
1063  *
1064  * Note: Pythia effectively classifies processes by the last digit
1065  * of the code (e.g. 101 -> 1, 102 -> 2, ...).
1066  *
1067  * The terminology "soft" vs "hard" is somewhat misleading:
1068  * Pythia's SoftQCD corresponds to a semi-perturbative (semi-hard)
1069  * model valid down to low pT, while HardQCD represents purely
1070  * perturbative processes and is not applicable over the full pT range.
1071  */
1072 
1073  switch (type) {
1075  final_state_success = hard_map_[idAB]->next(1);
1076  break;
1078  final_state_success = hard_map_[idAB]->next(5);
1079  break;
1081  final_state_success = hard_map_[idAB]->next(4);
1082  break;
1084  final_state_success = hard_map_[idAB]->next(3);
1085  break;
1086  default:
1087  logg[LPythia].error("Unknown string process required.");
1088  final_state_success = false;
1089  break;
1090  }
1091 
1092  logg[LPythia].debug("Pythia final state computed, success = ",
1093  final_state_success);
1094  if (!final_state_success) {
1095  return false;
1096  }
1097 
1098  auto valence_tags = compute_beam_valence_flags(*hard_map_[idAB]);
1099 
1100  for (auto& p : hard_map_[idAB]->event) {
1101  if (!p.isQuark() && !p.isDiquark() && !p.isGluon()) {
1102  continue;
1103  }
1104 
1105  if (valence_tags[p.index()] && (p.isQuark() || p.isDiquark())) {
1106  p.statusCode(static_cast<int>(p.isDiquark()
1109  } else {
1110  p.statusCode(static_cast<int>(LeadingStatus::NonLeadingParton));
1111  }
1112  }
1113  ParticleList new_intermediate_particles;
1114  ParticleList new_non_hadron_particles;
1115  Pythia8::Vec4 pSum = 0.;
1116  event_intermediate_.reset();
1117  /* Update the partonic intermediate state from PYTHIA output.
1118  * Note that hadronization will be performed separately,
1119  * after identification of strings and replacement of constituents. */
1120  for (int i = 0; i < hard_map_[idAB]->event.size(); i++) {
1121  if (hard_map_[idAB]->event[i].isFinal()) {
1122  const int pdgid = hard_map_[idAB]->event[i].id();
1123  Pythia8::Vec4 pquark = hard_map_[idAB]->event[i].p();
1124  const double mass = pquark.mCalc();
1125  const int status = hard_map_[idAB]->event[i].status();
1126  const int color = hard_map_[idAB]->event[i].col();
1127  const int anticolor = hard_map_[idAB]->event[i].acol();
1128 
1129  pSum += pquark;
1130  event_intermediate_.append(pdgid, status, color, anticolor, pquark, mass);
1131  }
1132  }
1133  // add junctions to the intermediate state if there is any.
1134  event_intermediate_.clearJunctions();
1135  for (int i = 0; i < hard_map_[idAB]->event.sizeJunction(); i++) {
1136  const int kind = hard_map_[idAB]->event.kindJunction(i);
1137  std::array<int, 3> col;
1138  for (int j = 0; j < 3; j++) {
1139  col[j] = hard_map_[idAB]->event.colJunction(i, j);
1140  }
1141  event_intermediate_.appendJunction(kind, col[0], col[1], col[2]);
1142  }
1143  /* The zeroth entry of event record is supposed to have the information
1144  * on the whole system. Specify the total momentum and invariant mass. */
1145  event_intermediate_[0].p(pSum);
1146  event_intermediate_[0].m(pSum.mCalc());
1147 
1148  const int elastic_side =
1151  : -1;
1152  if (elastic_side >= 0 &&
1153  PDGcodes_[elastic_side].get_decimal() != pdg_for_pythia[elastic_side]) {
1154  const int mapped_id = pdg_for_pythia[elastic_side];
1155  const int actual_id = PDGcodes_[elastic_side].get_decimal();
1156 
1157  int elastic_index = -1;
1158 
1159  for (int i = 1; i < event_intermediate_.size(); ++i) {
1160  const auto& p = event_intermediate_[i];
1161 
1162  if (p.status() == 14 && p.id() == mapped_id) {
1163  elastic_index = i;
1164  break;
1165  }
1166  }
1167 
1168  if (elastic_index < 0) {
1169  logg[LPythia].warn("Could not find elastic mapped hadron ", mapped_id,
1170  " to replace by ", actual_id);
1171  return false;
1172  }
1173 
1174  auto& elastic = event_intermediate_[elastic_index];
1175 
1176  std::vector<int> recoil_indices;
1177  Pythia8::Vec4 p_recoil_old;
1178 
1179  for (int i = 1; i < event_intermediate_.size(); ++i) {
1180  if (i == elastic_index)
1181  continue;
1182 
1183  const auto& p = event_intermediate_[i];
1184 
1185  recoil_indices.push_back(i);
1186  p_recoil_old += p.p();
1187  }
1188 
1189  if (recoil_indices.empty()) {
1190  event_intermediate_.list();
1191  logg[LPythia].warn(
1192  "Could not find recoil system for elastic mapped hadron ", mapped_id);
1193  return false;
1194  }
1195 
1196  Pythia8::Vec4 p_elastic_new = elastic.p();
1197  Pythia8::Vec4 p_recoil_new = p_recoil_old;
1198 
1199  const double m_elastic_new =
1201 
1202  const double m_recoil_system = p_recoil_old.mCalc();
1203 
1204  if (!Pythia8::pShift(p_elastic_new, p_recoil_new, m_elastic_new,
1205  m_recoil_system)) {
1206  logg[LPythia].warn(
1207  "Could not shift momenta when remapping elastic hadron from ",
1208  mapped_id, " to ", actual_id, ".");
1209  return false;
1210  }
1211 
1212  Pythia8::RotBstMatrix recoil_bst;
1213  recoil_bst.bstback(p_recoil_old);
1214  recoil_bst.bst(p_recoil_new);
1215 
1216  elastic.id(actual_id);
1217  elastic.m(m_elastic_new);
1218  elastic.p(p_elastic_new);
1219 
1220  for (const int idx : recoil_indices) {
1221  auto& recoiler = event_intermediate_[idx];
1222 
1223  Pythia8::Vec4 p_new = recoiler.p();
1224  p_new.rotbst(recoil_bst);
1225  recoiler.p(p_new);
1226  }
1227  excess_quark[elastic_side] = {0, 0, 0, 0, 0};
1228  excess_antiq[elastic_side] = {0, 0, 0, 0, 0};
1229  }
1230  /* Replace quark constituents according to the excess of valence quarks
1231  * and then rescale momenta of partons by constant factor
1232  * to fulfill the energy-momentum conservation. */
1233  bool correct_constituents =
1234  restore_constituent(event_intermediate_, excess_quark, excess_antiq);
1235  if (!correct_constituents) {
1236  logg[LPythia].debug("failed to find correct partonic constituents.");
1237  return false;
1238  }
1239  event_intermediate_.rotbst(to_cm_.inverse());
1240  int npart = event_intermediate_.size();
1241  int ipart = 0;
1242  while (ipart < npart) {
1243  const int pdgid = event_intermediate_[ipart].id();
1244  if (event_intermediate_[ipart].isFinal() &&
1245  !event_intermediate_[ipart].isParton() &&
1246  !hard_map_[idAB]->particleData.isOctetHadron(pdgid)) {
1247  logg[LPythia].debug("PDG ID from Pythia: ", pdgid);
1248  Pythia8::Vec4 momentum_pythia = event_intermediate_[ipart].p();
1249  FourVector momentum = make_smash_4vec(momentum_pythia);
1250 
1251  logg[LPythia].debug("4-momentum from Pythia: ", momentum);
1252  bool found_ptype =
1253  append_intermediate_list(pdgid, momentum, new_non_hadron_particles);
1254  if (!found_ptype) {
1255  logg[LPythia].warn("PDG ID ", pdgid,
1256  " does not exist in ParticleType - start over.");
1257  return false;
1258  }
1259  event_intermediate_.remove(ipart, ipart);
1260  npart -= 1;
1261  } else {
1262  ipart += 1;
1263  }
1264  }
1265 
1266  for (ParticleData& non_hadron : new_non_hadron_particles) {
1267  non_hadron.set_cross_section_scaling_factor(1.);
1268  non_hadron.set_formation_time(time_collision_);
1269  final_state_.push_back(non_hadron);
1270  }
1271  logg[LPythia].debug("Hard non-diff: partonic process gives ",
1272  event_intermediate_.size(), " partons.");
1273  bool find_forward_string = true;
1274  while (event_intermediate_.size() > 1) {
1275  Pythia8::Event string_event;
1276  string_event.init("Hard string", &pythia_hadron_->particleData);
1277  if (event_intermediate_.sizeJunction() > 0) {
1278  // identify string from a junction if there is any.
1279  compose_string_junction(find_forward_string, event_intermediate_,
1280  string_event);
1281  } else {
1282  /* identify string from a most forward or backward parton.
1283  * if there is no junction. */
1284  compose_string_parton(find_forward_string, event_intermediate_,
1285  string_event);
1286  }
1287  if (!string_above_threshold(string_event)) {
1288  return false;
1289  }
1290  string_parton_events_.push_back(string_event);
1291  find_forward_string = !find_forward_string;
1292  }
1293 
1294  return true;
1295 }
double mass() const
Definition: particletype.h:147
static PdgCode from_decimal(const int pdgcode_decimal)
Construct PDG code from decimal number.
Definition: pdgcode.h:339
pythia_map hard_map_
Map object to contain the different pythia objects.
@ NonLeadingParton
Standard PYTHIA status for non-leading partons that should be hadronized.
static int pdg_map_for_pythia(PdgCode &pdg)
Take pdg code and map onto particle specie which can be handled by PYTHIA.
std::optional< double > mpi_initialization_sqrts_
Optional center-of-mass energy used to initialize MPI-capable Pythia objects.
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...
bool string_above_threshold(const Pythia8::Event &event)
Check whether all strings in a PYTHIA event are above fragmentation threshold.
std::vector< bool > compute_beam_valence_flags(Pythia8::Pythia &pythia)
Compute flags identifying beam valence partons (quarks or diquarks) that act as leading partons after...
static bool append_intermediate_list(int pdgid, FourVector momentum, ParticleList &intermediate_particles)
append new particle from PYTHIA to a specific particle list
void init(const ParticleList &incoming, double tcoll)
initialization feed intial particles, time of collision and gamma factor of the center of mass.
static void find_excess_constituent(PdgCode &pdg_actual, PdgCode &pdg_mapped, std::array< int, 5 > &excess_quark, std::array< int, 5 > &excess_antiq)
Compare the valence quark contents of the actual and mapped hadrons and evaluate how many more consti...
void compose_string_parton(bool find_forward_string, Pythia8::Event &event_intermediate, Pythia8::Event &event_hadronize)
Identify a set of partons, which are connected to form a color-neutral string, from a given PYTHIA ev...
void compose_string_junction(bool &find_forward_string, Pythia8::Event &event_intermediate, Pythia8::Event &event_hadronize)
Identify a set of partons and junction(s), which are connected to form a color-neutral string,...
std::array< einhard::Logger<>, std::tuple_size< LogArea::AreaTuple >::value > & logg
An array that stores all pre-configured Logger objects.
Definition: logging.h:245
constexpr int maximum_rndm_seed_in_pythia
The maximum value of the random seed used in PYTHIA.
Definition: constants.h:114
@ StringHardSingleDiffractiveAX
See here for a short description.
@ StringHardNonDiffractive
See here for a short description.
@ StringHardSingleDiffractiveXB
See here for a short description.
@ StringHardDoubleDiffractive
See here for a short description.
std::string to_string(ThermodynamicQuantity quantity)
Convert a ThermodynamicQuantity enum value to its corresponding string.
Definition: stringify.cc:26
static constexpr int LPythia
Definition: stringprocess.h:27
Here is the call graph for this function:
Here is the caller graph for this function:

◆ next_BBbarAnn()

bool smash::StringProcess::next_BBbarAnn ( )
private

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

620  {
621  logg[LPythia].debug("Annihilation occurs between ", PDGcodes_[0], "+",
622  PDGcodes_[1], " at CM energy [GeV] ", sqrtsAB_);
623 
624  // check if the initial state is baryon-antibaryon pair.
625  PdgCode baryon = PDGcodes_[0], antibaryon = PDGcodes_[1];
626  if (baryon.baryon_number() == -1) {
627  std::swap(baryon, antibaryon);
628  }
629  if (baryon.baryon_number() != 1 || antibaryon.baryon_number() != -1) {
630  throw std::invalid_argument("Expected baryon-antibaryon pair.");
631  }
632 
633  // Count how many qqbar combinations are possible for each quark type
634  constexpr int n_q_types = 5; // u, d, s, c, b
635  std::vector<int> qcount_bar, qcount_antibar;
636  std::vector<int> n_combinations;
637  bool no_combinations = true;
638  for (int i = 0; i < n_q_types; i++) {
639  qcount_bar.push_back(baryon.net_quark_number(i + 1));
640  qcount_antibar.push_back(-antibaryon.net_quark_number(i + 1));
641  const int n_i = qcount_bar[i] * qcount_antibar[i];
642  n_combinations.push_back(n_i);
643  if (n_i > 0) {
644  no_combinations = false;
645  }
646  }
647 
648  /* if it is a BBbar pair but there is no qqbar pair to annihilate,
649  * nothing happens */
650  if (no_combinations) {
651  for (int i = 0; i < 2; i++) {
652  ParticleData new_particle(ParticleType::find(PDGcodes_[i]));
653  Pythia8::Vec4 pcom_pyth = make_pythia_4vec(pcom_[i]);
654  pcom_pyth.rotbst(to_cm_.inverse());
655  new_particle.set_4momentum(make_smash_4vec(pcom_pyth));
656  new_particle.set_cross_section_scaling_factor(1.);
657  new_particle.set_formation_time(time_collision_);
658  final_state_.push_back(new_particle);
659  }
660  return true;
661  }
662 
663  // Select qqbar pair to annihilate and remove it away
664  auto discrete_distr = random::discrete_dist<int>(n_combinations);
665  const int q_annihilate = discrete_distr() + 1;
666  qcount_bar[q_annihilate - 1]--;
667  qcount_antibar[q_annihilate - 1]--;
668 
669  // Get the remaining quarks and antiquarks
670  std::vector<int> remaining_quarks, remaining_antiquarks;
671  for (int i = 0; i < n_q_types; i++) {
672  for (int j = 0; j < qcount_bar[i]; j++) {
673  remaining_quarks.push_back(i + 1);
674  }
675  for (int j = 0; j < qcount_antibar[i]; j++) {
676  remaining_antiquarks.push_back(-(i + 1));
677  }
678  }
679  assert(remaining_quarks.size() == 2);
680  assert(remaining_antiquarks.size() == 2);
681 
682  const std::array<double, 2> mstr = {0.5 * sqrtsAB_, 0.5 * sqrtsAB_};
683 
684  // randomly select two quark-antiquark pairs
685  if (random::uniform_int(0, 1) == 0) {
686  std::swap(remaining_quarks[0], remaining_quarks[1]);
687  }
688  if (random::uniform_int(0, 1) == 0) {
689  std::swap(remaining_antiquarks[0], remaining_antiquarks[1]);
690  }
691  // Make sure it satisfies kinematical threshold constraint
692  bool kin_threshold_satisfied = true;
693  for (int i = 0; i < 2; i++) {
694  const double mstr_min =
695  pythia_hadron_->particleData.m0(remaining_quarks[i]) +
696  pythia_hadron_->particleData.m0(remaining_antiquarks[i]);
697  if (mstr_min > mstr[i]) {
698  kin_threshold_satisfied = false;
699  }
700  }
701  if (!kin_threshold_satisfied) {
702  return false;
703  }
704 
705  for (int i = 0; i < 2; i++) {
707  {remaining_quarks[i], remaining_antiquarks[i]}, 101 + i,
708  i == 0, true)) {
709  return false;
710  }
711  }
712  return true;
713 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ common_setup_pythia()

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

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

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

Definition at line 102 of file stringprocess.cc.

107  {
108  // choose parametrization for mass-dependent width
109  pythia_in->readString("ParticleData:modeBreitWigner = 4");
110 
111  // Global Lund fragmentation
112  pythia_in->readString("StringZ:aLund = " + std::to_string(stringz_a));
113  pythia_in->readString("StringZ:bLund = " + std::to_string(stringz_b));
114  pythia_in->readString("BeamRemnants:dampPopcorn = " +
117  pythia_in->readString("BeamRemnants:hardRemnantBaryon = on");
118  pythia_in->readString("BeamRemnants:aRemnantBaryon = " +
120  pythia_in->readString("BeamRemnants:bRemnantBaryon = " +
122  }
123  // transverse momentum spread in string fragmentation
124  pythia_in->readString("StringPT:sigma = " + std::to_string(string_sigma_T));
125  // diquark suppression factor in string fragmentation
126  pythia_in->readString("StringFlav:probQQtoQ = " +
127  std::to_string(diquark_supp));
128  // strangeness suppression factor in string fragmentation
129  pythia_in->readString("StringFlav:probStoUD = " +
130  std::to_string(strange_supp));
131  pythia_in->readString("StringFlav:popcornRate = " +
132  std::to_string(popcorn_rate));
133 
134  // manually set the parton distribution function
135  pythia_in->readString("PDF:pSet = 13");
136  pythia_in->readString("PDF:pSetB = 13");
137  pythia_in->readString("PDF:piSet = 1");
138  pythia_in->readString("PDF:piSetB = 1");
139  pythia_in->readString("Beams:idA = 2212");
140  pythia_in->readString("Beams:idB = 2212");
141  pythia_in->readString("Beams:eCM = 10.");
142 
143  // set PYTHIA random seed from outside
144  pythia_in->readString("Random:setSeed = on");
145  // suppress unnecessary output
146  pythia_in->readString("Print:quiet = on");
147  // No resonance decays, since the resonances will be handled by SMASH
148  pythia_in->readString("HadronLevel:Decay = off");
149  // set particle masses and widths in PYTHIA to be same with those in SMASH
150  for (auto& ptype : ParticleType::list_all()) {
151  int pdgid = ptype.pdgcode().get_decimal();
152  double mass_pole = ptype.mass();
153  double width_pole = ptype.width_at_pole();
154  // check if the particle species is in PYTHIA
155  if (pythia_in->particleData.isParticle(pdgid)) {
156  // set mass and width in PYTHIA
157  pythia_in->particleData.m0(pdgid, mass_pole);
158  pythia_in->particleData.mWidth(pdgid, width_pole);
159  } else if (pdgid == 310 || pdgid == 130) {
160  // set mass and width of Kaon-L and Kaon-S
161  pythia_in->particleData.m0(pdgid, kaon_mass);
162  pythia_in->particleData.mWidth(pdgid, 0.);
163  }
164  }
165 
166  // make energy-momentum conservation in PYTHIA more precise
167  pythia_in->readString("Check:epTolErr = 1e-6");
168  pythia_in->readString("Check:epTolWarn = 1e-8");
169 
170  if (use_monash_tune_) {
171  pythia_in->readString("Tune:ee = 7");
172  pythia_in->readString("Tune:pp = 14");
173  }
174 
175  for (const auto& setting : pythia_settings_) {
176  if (!pythia_in->readString(setting)) {
177  throw std::runtime_error(
178  "Failed to apply Pythia setting \"" + setting +
179  "\". Please check that it is a valid Pythia 8 setting.");
180  }
181  }
182 }
static const ParticleTypeList & list_all()
Definition: particletype.cc:51
constexpr double kaon_mass
Kaon mass in GeV.
Definition: constants.h:83
Here is the call graph for this function:
Here is the caller graph for this function:

◆ init_pythia_hadron_rndm()

void smash::StringProcess::init_pythia_hadron_rndm ( )
inline

Set PYTHIA random seeds to be desired values.

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

See also
smash::maximum_rndm_seed_in_pythia

Definition at line 435 of file stringprocess.h.

435  {
436  const int seed_new = random::uniform_int(1, maximum_rndm_seed_in_pythia);
437 
438  pythia_hadron_->rndm.init(seed_new);
439  logg[LPythia].debug("pythia_hadron_ : rndm is initialized with seed ",
440  seed_new);
441  }
Here is the call graph for this function:

◆ tag_leading_hadrons()

void smash::StringProcess::tag_leading_hadrons ( Pythia8::Event &  event)

Tag leading hadrons in a hadronized string.

After string fragmentation, this function identifies the hadrons that originate from the leading string endpoints and assigns them a custom status code (see LeadingStatus).

The procedure is:

  • identify the two string endpoint partons (quarks or diquarks),
  • boost the event into the string rest frame,
  • sort all final-state hadrons by longitudinal momentum,
  • associate each endpoint with the hadron closest to its end of the string,
  • assign a leading-hadron status based on the flavor content of the endpoint parton.

Diquark endpoints are processed before quark endpoints to ensure that leading baryons are preferentially associated with beam-remnant diquarks. A hadron can only be tagged once.

For diquark endpoints, only baryons with matching baryon-number sign are considered. Quark endpoints may tag either mesons or baryons, but baryons must again have a compatible baryon-number sign.

The event is temporarily transformed into the string rest frame during the identification procedure and restored to its original frame before returning.

Parameters
[in,out]eventHadronized Pythia event. The event is modified in-place by assigning custom status codes to identified leading hadrons.

Definition at line 865 of file stringprocess.cc.

865  {
866  // Find the two string endpoint partons.
867  int idx1 = -1;
868  int idx2 = -1;
869  const Pythia8::ParticleData& pd = pythia_hadron_->particleData;
870 
871  for (const auto& part : event) {
872  if (part.isQuark() || part.isDiquark()) {
873  if (idx1 < 0) {
874  idx1 = part.index();
875  } else {
876  idx2 = part.index();
877  break;
878  }
879  }
880  }
881 
882  if (idx1 < 0 || idx2 < 0) {
883  return;
884  }
885 
886  // Work in the string rest frame. This makes the leading hadrons the ones
887  // closest to the two string endpoints in longitudinal momentum.
888  Pythia8::RotBstMatrix toRest;
889  toRest.toCMframe(event[idx1].p(), event[idx2].p());
890  event.rotbst(toRest);
891 
892  // Collect all final-state hadrons and order them from backward to forward.
893  std::vector<int> hadrons;
894  hadrons.reserve(event.size());
895 
896  for (int i = 0; i < event.size(); ++i) {
897  if (event[i].isFinal() && event[i].isHadron()) {
898  hadrons.push_back(i);
899  }
900  }
901 
902  std::sort(hadrons.begin(), hadrons.end(),
903  [&](int a, int b) { return event[a].pz() < event[b].pz(); });
904 
905  // Identify the forward and backward string endpoints in the rest frame.
906  const int forward_endpoint =
907  event[idx1].pz() > event[idx2].pz() ? idx1 : idx2;
908  const int backward_endpoint = forward_endpoint == idx1 ? idx2 : idx1;
909 
910  auto matches_endpoint = [&](int endpoint, int hadron) {
911  const auto& end = event[endpoint];
912  const auto& h = event[hadron];
913 
914  // Do not allow the same hadron to be tagged by both endpoints.
915  if (is_leading(h)) {
916  return false;
917  }
918 
919  // A diquark endpoint should tag a leading baryon with the same
920  // baryon-number sign.
921  if (end.isDiquark()) {
922  return pd.isBaryon(h.id()) && h.id() * end.id() > 0;
923  }
924 
925  // If a quark endpoint tags a baryon, require a compatible baryon sign.
926  if (pd.isBaryon(h.id())) {
927  return h.id() * end.id() > 0;
928  }
929 
930  // Mesons are compatible with quark endpoints.
931  return true;
932  };
933 
934  auto find_edge_hadron = [&](int endpoint, bool forward) -> int {
935  // Search from the edge corresponding to this endpoint: largest pz for
936  // the forward endpoint, smallest pz for the backward endpoint.
937  if (forward) {
938  for (auto it = hadrons.rbegin(); it != hadrons.rend(); ++it) {
939  if (matches_endpoint(endpoint, *it)) {
940  return *it;
941  }
942  }
943  } else {
944  for (int h : hadrons) {
945  if (matches_endpoint(endpoint, h)) {
946  return h;
947  }
948  }
949  }
950 
951  return -1;
952  };
953 
954  auto tag_endpoint = [&](int endpoint, bool forward) {
955  // Only original leading partons should define leading hadrons.
956  if (!is_leading_parton(event[endpoint])) {
957  return;
958  }
959 
960  const int hadron = find_edge_hadron(endpoint, forward);
961 
962  if (hadron >= 0) {
963  event[hadron].status(
964  leading_hadron_status_from_endpoint(event[endpoint]));
965  }
966  };
967 
968  auto tag_if_diquark = [&](int endpoint, bool forward) {
969  if (event[endpoint].isDiquark()) {
970  tag_endpoint(endpoint, forward);
971  }
972  };
973 
974  auto tag_if_quark = [&](int endpoint, bool forward) {
975  if (!event[endpoint].isDiquark()) {
976  tag_endpoint(endpoint, forward);
977  }
978  };
979 
980  // Tag diquark endpoints first. This lets baryonic leading hadrons claim the
981  // appropriate edge hadrons before quark endpoints are considered.
982  tag_if_diquark(backward_endpoint, false);
983  tag_if_diquark(forward_endpoint, true);
984 
985  // Tag the remaining quark endpoints.
986  tag_if_quark(backward_endpoint, false);
987  tag_if_quark(forward_endpoint, true);
988 
989  // Restore the original event frame.
990  event.rotbst(toRest.inverse());
991 }
bool is_leading_parton(const Pythia8::Particle &p)
Check whether a particle is tagged as a leading parton.
bool is_leading(const Pythia8::Particle &p)
Check whether a particle is tagged as originating from a leading endpoint.
int leading_hadron_status_from_endpoint(const Pythia8::Particle &end)
Determine the custom leading-hadron status code from a string endpoint.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ make_smash_4vec()

static FourVector smash::StringProcess::make_smash_4vec ( const Pythia8::Vec4 &  p)
inlinestatic

Convert a PYTHIA four-vector into a SMASH four-vector.

Parameters
[in]pPYTHIA four-vector.
Returns
Corresponding SMASH four-vector.

Definition at line 535 of file stringprocess.h.

535  {
536  return FourVector(p.e(), p.px(), p.py(), p.pz());
537  }
Here is the caller graph for this function:

◆ make_pythia_4vec()

static Pythia8::Vec4 smash::StringProcess::make_pythia_4vec ( const FourVector p)
inlinestatic

Convert a SMASH four-vector into a PYTHIA four-vector.

Parameters
[in]pSMASH four-vector.
Returns
Corresponding PYTHIA four-vector.

Definition at line 545 of file stringprocess.h.

545  {
546  return Pythia8::Vec4(p.x1(), p.x2(), p.x3(), p.x0());
547  }
Here is the caller graph for this function:

◆ next()

bool smash::StringProcess::next ( ProcessType  type)

Generate the next string process for a given process type.

Parameters
[in]typeType of string process to generate.
Returns
Whether the process was successfully generated.

Definition at line 259 of file stringprocess.cc.

259  {
260  string_parton_events_.clear();
261  final_state_.clear();
262 
263  bool parton_level_success = false;
264 
265  switch (type) {
267  parton_level_success = next_NDiffSoft();
268  break;
270  parton_level_success = next_SDiff(true);
271  break;
273  parton_level_success = next_SDiff(false);
274  break;
276  parton_level_success = next_DDiff();
277  break;
279  parton_level_success = next_BBbarAnn();
280  break;
285  parton_level_success = next_Hard(type);
286  break;
287  default:
288  logg[LPythia].error("Unknown string process required.");
289  return false;
290  }
291 
292  if (!parton_level_success) {
293  return false;
294  }
295 
296  for (const Pythia8::Event& string_event : string_parton_events_) {
297  auto hadrons = hadronize(string_event);
298 
299  if (!hadrons) {
300  final_state_.clear();
301  return false;
302  }
303 
304  final_state_.insert(final_state_.end(), hadrons->begin(), hadrons->end());
305  }
306 
307  return true;
308 }
bool next_SDiff(bool is_AB_to_AX)
Single-diffractive process is based on single pomeron exchange described in Ingelman:1984ns .
bool next_NDiffSoft()
Soft Non-diffractive process is modelled in accordance with dual-topological approach Capella:1978ig ...
bool next_DDiff()
Double-diffractive process ( A + B -> X + X ) is similar to the single-diffractive process,...
std::optional< ParticleList > hadronize(const Pythia8::Event &string_evt)
Hadronize a single partonic string configuration using Pythia8 and convert the produced hadrons into ...
bool next_Hard(ProcessType type)
Hard Non-diffractive process is based on PYTHIA 8 with partonic showers and interactions.
bool next_BBbarAnn()
Baryon-antibaryon annihilation process Based on what UrQMD Bass:1998ca , Bleicher:1999xi does,...
@ StringSoftDoubleDiffractive
See here for a short description.
@ StringSoftSingleDiffractiveXB
See here for a short description.
@ StringSoftAnnihilation
See here for a short description.
@ StringSoftNonDiffractive
See here for a short description.
@ StringSoftSingleDiffractiveAX
See here for a short description.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ string_above_threshold()

bool smash::StringProcess::string_above_threshold ( const Pythia8::Event &  event)

Check whether all strings in a PYTHIA event are above fragmentation threshold.

Parameters
[in]eventPYTHIA event record containing the string partons.
Returns
True if all strings are above threshold.

Definition at line 1350 of file stringprocess.cc.

1350  {
1351  const double string_mass = event[0].mCalc();
1352  const auto& particle_data = pythia_hadron_->particleData;
1353 
1354  std::vector<int> endpoints;
1355  endpoints.reserve(event.size());
1356 
1357  for (const Pythia8::Particle& p : event) {
1358  if (!p.isFinal() || p.isGluon() || !p.isParton()) {
1359  continue;
1360  }
1361 
1362  const int id = p.id();
1363 
1364  if (!particle_data.isQuark(id) && !particle_data.isDiquark(id)) {
1365  logg[LPythia].error("Colored non-quark/diquark in threshold check: id=",
1366  id, ", col=", p.col(), ", acol=", p.acol());
1367  return false;
1368  }
1369 
1370  endpoints.push_back(id);
1371  }
1372 
1373  // Closed gluon string.
1374  if (endpoints.size() < 2) {
1375  return string_mass > pion_mass * 2.0;
1376  }
1377 
1378  // Ordinary open string.
1379  if (endpoints.size() == 2) {
1380  return string_mass > estimate_string_threshold(endpoints[0], endpoints[1]);
1381  }
1382 
1383  // Baryonic/antibaryonic endpoint: combine two same-sign quarks.
1384  if (endpoints.size() == 3) {
1385  for (std::size_t i = 0; i < endpoints.size(); ++i) {
1386  for (std::size_t j = i + 1; j < endpoints.size(); ++j) {
1387  const int id_i = endpoints[i];
1388  const int id_j = endpoints[j];
1389 
1390  if (!particle_data.isQuark(id_i) || !particle_data.isQuark(id_j)) {
1391  continue;
1392  }
1393 
1394  if (id_i * id_j < 0) {
1395  continue;
1396  }
1397 
1398  const int diquark_id = diquark_from_quarks(id_i, id_j);
1399 
1400  const std::size_t k = 3 - i - j;
1401  const int remaining_id = endpoints[k];
1402 
1403  return string_mass >
1404  estimate_string_threshold(diquark_id, remaining_id);
1405  }
1406  }
1407 
1408  logg[LPythia].error(
1409  "Cannot reduce 3 string endpoints to quark-diquark "
1410  "threshold: ",
1411  endpoints[0], ", ", endpoints[1], ", ", endpoints[2]);
1412  return false;
1413  }
1414 
1415  logg[LPythia].error(
1416  "Unexpected number of string endpoints in threshold check: ",
1417  endpoints.size());
1418  return false;
1419 }
static int diquark_from_quarks(int q1, int q2)
Construct diquark from two quarks.
constexpr double pion_mass
Pion mass in GeV.
Definition: constants.h:76
Here is the call graph for this function:
Here is the caller graph for this function:

◆ estimate_string_threshold()

double smash::StringProcess::estimate_string_threshold ( int  p_left,
int  p_right 
)

Estimate the minimum invariant mass required for a string to fragment.

Parameters
[in]p_leftIndex of the left string endpoint in the PYTHIA event.
[in]p_rightIndex of the right string endpoint in the PYTHIA event.
Returns
Estimated string threshold mass [GeV].

Definition at line 1297 of file stringprocess.cc.

1298  {
1299  constexpr double fragmentation_margin = 2.0 * pion_mass; // GeV
1300 
1301  auto& particle_data = pythia_hadron_->particleData;
1302 
1303  const bool left_is_quark = particle_data.isQuark(left_endpoint_id);
1304  const bool right_is_quark = particle_data.isQuark(right_endpoint_id);
1305  const bool left_is_diquark = particle_data.isDiquark(left_endpoint_id);
1306  const bool right_is_diquark = particle_data.isDiquark(right_endpoint_id);
1307 
1308  if (!(left_is_quark || left_is_diquark) ||
1309  !(right_is_quark || right_is_diquark)) {
1310  throw std::invalid_argument(
1311  "String threshold estimate requires quark or diquark endpoints.");
1312  }
1313 
1314  if (left_is_diquark && right_is_diquark) {
1315  const int lightest_left_baryon =
1316  pythia_stringflav_.combineToLightest(left_endpoint_id, 2); // u
1317  const int lightest_right_baryon =
1318  pythia_stringflav_.combineToLightest(right_endpoint_id, -2); // anti-u
1319 
1320  return particle_data.m0(lightest_left_baryon) +
1321  particle_data.m0(lightest_right_baryon) + fragmentation_margin;
1322  }
1323 
1324  const int lightest_hadron =
1325  pythia_stringflav_.combineToLightest(left_endpoint_id, right_endpoint_id);
1326 
1327  const PdgCode pdg = PdgCode::from_decimal(lightest_hadron);
1328  return ParticleType::find(pdg).mass() + fragmentation_margin;
1329 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_color_by_type()

void smash::StringProcess::set_color_by_type ( Pythia8::Particle &  p,
int  color 
)

Set the color or anticolor index of a particle according to its type.

Quarks receive a color index, antiquarks receive an anticolor index, and diquarks are treated according to their PYTHIA color-flow convention.

Parameters
[out]pParticle whose color information is modified.
[in]colorColor tag to assign.

Definition at line 1331 of file stringprocess.cc.

1331  {
1332  const int id = p.id();
1333  const bool is_anti = (id < 0);
1334 
1335  const auto& pd = pythia_hadron_->particleData;
1336  const bool is_quark = pd.isQuark(id);
1337  const bool is_diquark = pd.isDiquark(id);
1338 
1339  if ((is_quark && !is_anti) || (is_diquark && is_anti)) {
1340  // quark or antidiquark: color flows out
1341  p.cols(color, 0);
1342  } else if ((is_quark && is_anti) || (is_diquark && !is_anti)) {
1343  // antiquark or diquark: color flows in
1344  p.cols(0, color);
1345  } else {
1346  throw std::runtime_error("Cannot set color: not a quark or diquark (id=" +
1347  std::to_string(id) + ")");
1348  }
1349 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ hadronize()

std::optional< ParticleList > smash::StringProcess::hadronize ( const Pythia8::Event &  string_evt)

Hadronize a single partonic string configuration using Pythia8 and convert the produced hadrons into SMASH particles.

The input event is interpreted as a single color-singlet string system. Fragmentation is performed in the string rest frame. The produced hadrons are converted to SMASH ParticleData objects, assigned formation times and cross-section scaling factors, and finally boosted out of the string rest frame.

Leading hadrons originating from valence quark or diquark endpoints may be identified and assigned reduced cross sections according to the leading-hadron prescription.

Parameters
[in]string_evtPartonic string event to hadronize.
Returns
List of fragmented hadrons on success.
std::nullopt if fragmentation or particle conversion fails.

Definition at line 310 of file stringprocess.cc.

311  {
312  ParticleList intermediate_particles;
313  // usually 0 is "system", so need at least indices 1 and 2
314  if (string_evt.size() < 3) {
315  logg[LPythia].error("String event too small to hadronize.");
316  return std::nullopt;
317  }
318 
319  bool has_leading_parton = false;
320 
321  const bool has_junction = string_evt.sizeJunction() > 0;
322 
323  for (const Pythia8::Particle& particle : string_evt) {
324  if (is_leading_parton(particle)) {
325  has_leading_parton = true;
326  break;
327  }
328  }
329 
330  const bool has_leading_and_is_open = has_leading_parton && !has_junction;
331 
332  pythia_hadron_->event.reset();
333  pythia_hadron_->event[0].p(string_evt[0].p());
334  pythia_hadron_->event[0].m(string_evt[0].p().mCalc());
335  for (int i = 1; i < string_evt.size(); ++i) {
336  pythia_hadron_->event.append(string_evt[i]);
337  }
338 
339  pythia_hadron_->event.clearJunctions();
340  for (int i = 0; i < string_evt.sizeJunction(); ++i) {
341  pythia_hadron_->event.appendJunction(
342  string_evt.kindJunction(i), string_evt.colJunction(i, 0),
343  string_evt.colJunction(i, 1), string_evt.colJunction(i, 2));
344  }
345 
346  const Pythia8::Vec4 p_str = string_evt[0].p();
347 
348  Pythia8::RotBstMatrix to_string_rest;
349  to_string_rest.bstback(p_str);
350 
351  pythia_hadron_->event.rotbst(to_string_rest);
352 
353  if (!pythia_hadron_->forceHadronLevel(false)) {
354  pythia_hadron_->event.list();
355  logg[LPythia].error("Pythia fragmentation failed for one string.");
356  return std::nullopt;
357  }
358 
359  if (has_leading_and_is_open) {
361  }
362 
363  const FourVector pString_smash(
364  p_str.e(), ThreeVector(p_str.px(), p_str.py(), p_str.pz()));
365 
366  const double m2 = pString_smash.sqr();
367 
368  if (m2 <= 0.0) {
369  logg[LPythia].error("String has non-positive invariant mass.");
370  return std::nullopt;
371  }
372 
373  // evecLong: unit vector along string momentum
374  // fallback if |p| ~ 0
375  ThreeVector evecLong(p_str.px(), p_str.py(), p_str.pz());
376 
377  const double pabs = evecLong.abs();
378 
379  if (pabs > 1e-12) {
380  evecLong = evecLong / pabs;
381  } else {
382  evecLong = ThreeVector(0.0, 0.0, 1.0);
383  }
384 
385  // Build intermediate SMASH particles from final hadrons
386  intermediate_particles.reserve(pythia_hadron_->event.size());
387  for (int i = 0; i < pythia_hadron_->event.size(); ++i) {
388  const auto& particle = pythia_hadron_->event[i];
389 
390  if (!(particle.isFinal() && particle.isHadron())) {
391  continue;
392  }
393 
394  const FourVector mom_smash = make_smash_4vec(particle.p());
395 
396  int particle_id = particle.id();
397  convert_KaonLS(particle_id);
398 
399  if (!append_intermediate_list(particle_id, mom_smash,
400  intermediate_particles)) {
401  logg[LPythia].error("Unknown hadron in SMASH during hadronization: PDG=",
402  particle.id());
403 
404  return std::nullopt;
405  }
406 
407  if (is_leading_from_diquark(particle)) {
408  intermediate_particles.back().set_cross_section_scaling_factor(
409  2.0 / 3.0 * additional_xsec_supp_);
410 
411  } else if (is_leading_from_quark(particle)) {
412  intermediate_particles.back().set_cross_section_scaling_factor(
413  (pythia_hadron_->particleData.isBaryon(particle.id()) ? 1.0 / 3.0
414  : 0.5) *
416  } else {
417  intermediate_particles.back().set_cross_section_scaling_factor(0.0);
418  }
419  }
420 
421  if (intermediate_particles.empty()) {
422  logg[LPythia].error("Hadronization produced no final hadrons.");
423  return std::nullopt;
424  }
425 
426  const bool should_assign_scaling = has_junction && has_leading_parton;
427 
428  form_intermediate_particles(intermediate_particles, pString_smash, evecLong,
429  additional_xsec_supp_, should_assign_scaling);
430 
431  return intermediate_particles;
432 }
static void convert_KaonLS(int &pythia_id)
convert Kaon-L or Kaon-S into K0 or Anti-K0
void tag_leading_hadrons(Pythia8::Event &event)
Tag leading hadrons in a hadronized string.
void form_intermediate_particles(ParticleList &intermediate_particles, const FourVector &pString, const ThreeVector &evecLong, double additional_xsec_supp=1.0, bool find_and_scale_leading=true)
Set formation times and cross-section scaling factors for fragmented hadrons as described in Andersso...
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cross_sections_diffractive()

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

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

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

619  {
620  // This threshold magic is following Pythia. Todo(ryu): take care of this.
621  double sqrts_threshold = 2. * (1. + 1.0e-6);
622  /* In the case of mesons, the corresponding vector meson masses
623  * are used to evaluate the energy threshold. */
624  const int pdg_a_mod =
625  (std::abs(pdg_a) > 1000) ? pdg_a : 10 * (std::abs(pdg_a) / 10) + 3;
626  const int pdg_b_mod =
627  (std::abs(pdg_b) > 1000) ? pdg_b : 10 * (std::abs(pdg_b) / 10) + 3;
628  sqrts_threshold += pythia_hadron_->particleData.m0(pdg_a_mod) +
629  pythia_hadron_->particleData.m0(pdg_b_mod);
630  /* Constant cross-section for sub-processes below threshold equal to
631  * cross-section at the threshold. */
632  if (sqrt_s < sqrts_threshold) {
633  sqrt_s = sqrts_threshold;
634  }
635  pythia_sigmatot_.calc(pdg_a, pdg_b, sqrt_s);
636  return {pythia_sigmatot_.sigmaAX(), pythia_sigmatot_.sigmaXB(),
637  pythia_sigmatot_.sigmaXX()};
638  }
Here is the caller graph for this function:

◆ set_pmin_gluon_lightcone()

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

set the minimum lightcone momentum scale carried by gluon.

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

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

Parameters
p_light_cone_mina value that we want to use for pmin_gluon_lightcone_.

Definition at line 654 of file stringprocess.h.

654  {
655  pmin_gluon_lightcone_ = p_light_cone_min;
656  }

◆ set_pow_fgluon()

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

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

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

Definition at line 664 of file stringprocess.h.

664 { pow_fgluon_beta_ = betapow; }

◆ set_pow_fquark()

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

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

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

Definition at line 673 of file stringprocess.h.

673  {
674  pow_fquark_alpha_ = alphapow;
675  pow_fquark_beta_ = betapow;
676  }

◆ set_sigma_qperp_()

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

set the average amount of transverse momentum transfer sigma_qperp_.

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

Definition at line 681 of file stringprocess.h.

681 { sigma_qperp_ = sigma_qperp; }

◆ set_tension_string()

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

set the string tension, which is used in form_intermediate_particles.

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

Definition at line 686 of file stringprocess.h.

686  {
687  kappa_tension_string_ = kappa_string;
688  }

◆ set_mpi_initialization_sqrts()

void smash::StringProcess::set_mpi_initialization_sqrts ( double  sqrts)
inline

Set the center-of-mass energy used to initialize MPI-capable Pythia objects.

If no value is set, the initialization energy is determined from the incoming hadrons.

Parameters
sqrtsCenter-of-mass energy [GeV] used for MPI initialization.

Definition at line 699 of file stringprocess.h.

699  {
701  }

◆ init()

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

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

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

Definition at line 226 of file stringprocess.cc.

226  {
227  PDGcodes_[0] = incoming[0].pdgcode();
228  PDGcodes_[1] = incoming[1].pdgcode();
229  massA_ = incoming[0].effective_mass();
230  massB_ = incoming[1].effective_mass();
231 
232  plab_[0] = incoming[0].momentum();
233  plab_[1] = incoming[1].momentum();
234 
235  sqrtsAB_ = (plab_[0] + plab_[1]).abs();
236  ucomAB_ = (plab_[0] + plab_[1]) / sqrtsAB_;
238 
239  const Pythia8::Vec4 pA_lab = make_pythia_4vec(plab_[0]);
240  const Pythia8::Vec4 pB_lab = make_pythia_4vec(plab_[1]);
241 
242  to_cm_.reset();
243  to_cm_.toCMframe(pA_lab, pB_lab);
244 
245  const Pythia8::Vec4 pA_cm = to_cm_ * pA_lab;
246  const Pythia8::Vec4 pB_cm = to_cm_ * pB_lab;
247 
248  pcom_[0] = make_smash_4vec(pA_cm);
249  pcom_[1] = make_smash_4vec(pB_cm);
250  ThreeVector evec_polar(pA_cm.px(), pA_cm.py(), pA_cm.pz());
251  evec_polar /= std::sqrt(evec_polar.sqr());
252 
255 
256  time_collision_ = tcoll;
257 }
ThreeVector velocity() const
Get the velocity (3-vector divided by zero component).
Definition: fourvector.h:333
FourVector ucomAB_
velocity four vector of the center of mass in the lab frame
Definition: stringprocess.h:74
ThreeVector vcomAB_
velocity three vector of the center of mass in the lab frame
Definition: stringprocess.h:76
void compute_incoming_lightcone_momenta()
compute the lightcone momenta of incoming particles where the longitudinal direction is set to be sam...
static void make_orthonormal_basis(ThreeVector &evec_polar, std::array< ThreeVector, 3 > &evec_basis)
compute three orthonormal basis vectors from unit vector in the longitudinal direction
std::array< FourVector, 2 > plab_
momenta of incoming particles in the lab frame [GeV]
Definition: stringprocess.h:70
Here is the call graph for this function:
Here is the caller graph for this function:

◆ make_orthonormal_basis()

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

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

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

Definition at line 2169 of file stringprocess.cc.

2170  {
2171  assert(std::fabs(evec_polar.sqr() - 1.) < really_small);
2172 
2173  if (std::abs(evec_polar.x3()) < (1. - 1.0e-8)) {
2174  double ex, ey, et;
2175  double theta, phi;
2176 
2177  // evec_basis[0] is set to be longitudinal direction
2178  evec_basis[0] = evec_polar;
2179 
2180  theta = std::acos(evec_basis[0].x3());
2181 
2182  ex = evec_basis[0].x1();
2183  ey = evec_basis[0].x2();
2184  et = std::sqrt(ex * ex + ey * ey);
2185  if (ey > 0.) {
2186  phi = std::acos(ex / et);
2187  } else {
2188  phi = -std::acos(ex / et);
2189  }
2190 
2191  /* The transverse plane is spanned
2192  * by evec_basis[1] and evec_basis[2]. */
2193  evec_basis[1].set_x1(std::cos(theta) * std::cos(phi));
2194  evec_basis[1].set_x2(std::cos(theta) * std::sin(phi));
2195  evec_basis[1].set_x3(-std::sin(theta));
2196 
2197  evec_basis[2].set_x1(-std::sin(phi));
2198  evec_basis[2].set_x2(std::cos(phi));
2199  evec_basis[2].set_x3(0.);
2200  } else {
2201  // if evec_polar is very close to the z axis
2202  if (evec_polar.x3() > 0.) {
2203  evec_basis[1] = ThreeVector(1., 0., 0.);
2204  evec_basis[2] = ThreeVector(0., 1., 0.);
2205  evec_basis[0] = ThreeVector(0., 0., 1.);
2206  } else {
2207  evec_basis[1] = ThreeVector(0., 1., 0.);
2208  evec_basis[2] = ThreeVector(1., 0., 0.);
2209  evec_basis[0] = ThreeVector(0., 0., -1.);
2210  }
2211  }
2212 
2213  assert(std::fabs(evec_basis[1] * evec_basis[2]) < really_small);
2214  assert(std::fabs(evec_basis[2] * evec_basis[0]) < really_small);
2215  assert(std::fabs(evec_basis[0] * evec_basis[1]) < really_small);
2216 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ compute_incoming_lightcone_momenta()

void smash::StringProcess::compute_incoming_lightcone_momenta ( )

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

Definition at line 2218 of file stringprocess.cc.

2218  {
2219  PPosA_ = (pcom_[0].x0() + evecBasisAB_[0] * pcom_[0].threevec()) * M_SQRT1_2;
2220  PNegA_ = (pcom_[0].x0() - evecBasisAB_[0] * pcom_[0].threevec()) * M_SQRT1_2;
2221  PPosB_ = (pcom_[1].x0() + evecBasisAB_[0] * pcom_[1].threevec()) * M_SQRT1_2;
2222  PNegB_ = (pcom_[1].x0() - evecBasisAB_[0] * pcom_[1].threevec()) * M_SQRT1_2;
2223 }
Here is the caller graph for this function:

◆ find_excess_constituent()

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

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

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

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

Definition at line 1420 of file stringprocess.cc.

1423  {
1424  /* decompose PDG id of the actual hadron and mapped one
1425  * to get the valence quark constituents */
1426  std::array<int, 3> qcontent_actual = pdg_actual.quark_content();
1427  std::array<int, 3> qcontent_mapped = pdg_mapped.quark_content();
1428 
1429  excess_quark = {0, 0, 0, 0, 0};
1430  excess_antiq = {0, 0, 0, 0, 0};
1431  for (int i = 0; i < 3; i++) {
1432  if (qcontent_actual[i] > 0) { // quark content of the actual hadron
1433  int j = qcontent_actual[i] - 1;
1434  excess_quark[j] += 1;
1435  }
1436 
1437  if (qcontent_mapped[i] > 0) { // quark content of the mapped hadron
1438  int j = qcontent_mapped[i] - 1;
1439  excess_quark[j] -= 1;
1440  }
1441 
1442  if (qcontent_actual[i] < 0) { // antiquark content of the actual hadron
1443  int j = std::abs(qcontent_actual[i]) - 1;
1444  excess_antiq[j] += 1;
1445  }
1446 
1447  if (qcontent_mapped[i] < 0) { // antiquark content of the mapped hadron
1448  int j = std::abs(qcontent_mapped[i]) - 1;
1449  excess_antiq[j] -= 1;
1450  }
1451  }
1452 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ replace_constituent()

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

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

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

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

Definition at line 1454 of file stringprocess.cc.

1455  {
1456  // If the particle is neither quark nor diquark, nothing to do.
1457  if (!particle.isQuark() && !particle.isDiquark()) {
1458  return;
1459  }
1460 
1461  // If there is no excess of constituents, nothing to do.
1462  const std::array<int, 5> excess_null = {0, 0, 0, 0, 0};
1463  if (excess_constituent == excess_null) {
1464  return;
1465  }
1466 
1467  int nq = 0;
1468  std::array<int, 2> pdgid = {0, 0};
1469  int spin_deg = 0;
1470  int pdgid_new = 0;
1471  if (particle.isQuark()) {
1472  nq = 1;
1473  pdgid[0] = particle.id();
1474  } else if (particle.isDiquark()) {
1475  nq = 2;
1476  quarks_from_diquark(particle.id(), pdgid[0], pdgid[1], spin_deg);
1477  }
1478 
1479  for (int iq = 0; iq < nq; iq++) {
1480  int jq = std::abs(pdgid[iq]) - 1;
1481  int k_select = 0;
1482  std::vector<int> k_found;
1483  k_found.clear();
1484  // check if the constituent needs to be converted.
1485  if (excess_constituent[jq] < 0) {
1486  for (int k = 0; k < 5; k++) {
1487  // check which specie it can be converted into.
1488  if (k != jq && excess_constituent[k] > 0) {
1489  k_found.push_back(k);
1490  }
1491  }
1492  }
1493 
1494  // make a random selection of specie and update the excess of constituent.
1495  if (k_found.size() > 0) {
1496  const int l =
1497  random::uniform_int(0, static_cast<int>(k_found.size()) - 1);
1498  k_select = k_found[l];
1499  /* flavor jq + 1 is converted into k_select + 1
1500  * and excess_constituent is updated. */
1501  pdgid[iq] = pdgid[iq] > 0 ? k_select + 1 : -(k_select + 1);
1502  excess_constituent[jq] += 1;
1503  excess_constituent[k_select] -= 1;
1504  }
1505  }
1506 
1507  // determine PDG id of the converted parton.
1508  if (particle.isQuark()) {
1509  pdgid_new = pdgid[0];
1510  } else if (particle.isDiquark()) {
1511  if (std::abs(pdgid[0]) < std::abs(pdgid[1])) {
1512  std::swap(pdgid[0], pdgid[1]);
1513  }
1514 
1515  pdgid_new = std::abs(pdgid[0]) * 1000 + std::abs(pdgid[1]) * 100;
1516  if (std::abs(pdgid[0]) == std::abs(pdgid[1])) {
1517  pdgid_new += 3;
1518  } else {
1519  pdgid_new += spin_deg;
1520  }
1521 
1522  if (particle.id() < 0) {
1523  pdgid_new *= -1;
1524  }
1525  }
1526  logg[LPythia].debug(" parton id = ", particle.id(), " is converted to ",
1527  pdgid_new);
1528 
1529  // update the constituent mass and energy.
1530  Pythia8::Vec4 pquark = particle.p();
1531  double mass_new = pythia_hadron_->particleData.m0(pdgid_new);
1532  double e_new = std::sqrt(mass_new * mass_new + pquark.pAbs() * pquark.pAbs());
1533  // update the particle object.
1534  particle.id(pdgid_new);
1535  particle.e(e_new);
1536  particle.m(mass_new);
1537 }
static void quarks_from_diquark(int diquark, int &q1, int &q2, int &deg_spin)
find two quarks from a diquark.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ find_total_number_constituent()

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

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

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

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

Definition at line 1539 of file stringprocess.cc.

1541  {
1542  for (int iflav = 0; iflav < 5; iflav++) {
1543  nquark_total[iflav] = 0;
1544  nantiq_total[iflav] = 0;
1545  }
1546 
1547  for (int ip = 1; ip < event_intermediate.size(); ip++) {
1548  if (!event_intermediate[ip].isFinal()) {
1549  continue;
1550  }
1551  const int pdgid = event_intermediate[ip].id();
1552  if (pdgid > 0) {
1553  // quarks
1554  for (int iflav = 0; iflav < 5; iflav++) {
1555  nquark_total[iflav] +=
1556  pythia_hadron_->particleData.nQuarksInCode(pdgid, iflav + 1);
1557  }
1558  } else {
1559  // antiquarks
1560  for (int iflav = 0; iflav < 5; iflav++) {
1561  nantiq_total[iflav] += pythia_hadron_->particleData.nQuarksInCode(
1562  std::abs(pdgid), iflav + 1);
1563  }
1564  }
1565  }
1566 }
Here is the caller graph for this function:

◆ splitting_gluon_qqbar()

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

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

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

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

Definition at line 1568 of file stringprocess.cc.

1571  {
1572  Pythia8::Vec4 pSum = event_intermediate[0].p();
1573 
1574  /* compute total number of quark and antiquark constituents
1575  * in the whole system. */
1576  find_total_number_constituent(event_intermediate, nquark_total, nantiq_total);
1577 
1578  for (int iflav = 0; iflav < 5; iflav++) {
1579  /* Find how many constituent will be in the system after
1580  * changing the flavors.
1581  * Note that nquark_total is number of constituent right after
1582  * the pythia event (with mapped incoming hadrons), while the excess
1583  * shows how many constituents we have more or less that nquark_total. */
1584  int nquark_final =
1585  excess_constituent[0][iflav] + excess_constituent[1][iflav];
1586  if (sign_constituent) {
1587  nquark_final += nquark_total[iflav];
1588  } else {
1589  nquark_final += nantiq_total[iflav];
1590  }
1591  /* Therefore, nquark_final should not be negative.
1592  * negative nquark_final means that it will not be possible to
1593  * find a constituent to change the flavor. */
1594  bool enough_quark = nquark_final >= 0;
1595  /* If that is the case, a gluon will be splitted into
1596  * a quark-antiquark pair with the desired flavor. */
1597  if (!enough_quark) {
1598  logg[LPythia].debug(" not enough constituents with flavor ", iflav + 1,
1599  " : try to split a gluon to qqbar.");
1600  for (int ic = 0; ic < std::abs(nquark_final); ic++) {
1601  /* Since each incoming hadron has its own count of the excess,
1602  * it is necessary to find which one is problematic. */
1603  int ih_mod = -1;
1604  if (excess_constituent[0][iflav] < 0) {
1605  ih_mod = 0;
1606  } else {
1607  ih_mod = 1;
1608  }
1609 
1610  /* find the most forward or backward gluon
1611  * depending on which incoming hadron is found to be an issue. */
1612  int iforward = 1;
1613  for (int ip = 2; ip < event_intermediate.size(); ip++) {
1614  if (!event_intermediate[ip].isFinal() ||
1615  !event_intermediate[ip].isGluon()) {
1616  continue;
1617  }
1618 
1619  const double y_gluon_current = event_intermediate[ip].y();
1620  const double y_gluon_forward = event_intermediate[iforward].y();
1621  if ((ih_mod == 0 && y_gluon_current > y_gluon_forward) ||
1622  (ih_mod == 1 && y_gluon_current < y_gluon_forward)) {
1623  iforward = ip;
1624  }
1625  }
1626 
1627  if (!event_intermediate[iforward].isGluon()) {
1628  logg[LPythia].debug("There is no gluon to split into qqbar.");
1629  return false;
1630  }
1631 
1632  // four momentum of the original gluon
1633  Pythia8::Vec4 pgluon = event_intermediate[iforward].p();
1634 
1635  const int pdgid = iflav + 1;
1636  const double mass = pythia_hadron_->particleData.m0(pdgid);
1637  const int status = event_intermediate[iforward].status();
1638  /* color and anticolor indices.
1639  * the color index of gluon goes to the quark, while
1640  * the anticolor index goes to the antiquark */
1641  const int col = event_intermediate[iforward].col();
1642  const int acol = event_intermediate[iforward].acol();
1643 
1644  // three momenta of quark and antiquark
1645  std::array<double, 2> px_quark;
1646  std::array<double, 2> py_quark;
1647  std::array<double, 2> pz_quark;
1648  // energies of quark and antiquark
1649  std::array<double, 2> e_quark;
1650  // four momenta of quark and antiquark
1651  std::array<Pythia8::Vec4, 2> pquark;
1652  // transverse momentum scale of string fragmentation
1653  const double sigma_qt_frag = pythia_hadron_->parm("StringPT:sigma");
1654  // sample relative transverse momentum between quark and antiquark
1655  const double qx = random::normal(0., sigma_qt_frag * M_SQRT1_2);
1656  const double qy = random::normal(0., sigma_qt_frag * M_SQRT1_2);
1657  // setup kinematics
1658  for (int isign = 0; isign < 2; isign++) {
1659  /* As the simplest assumption, the three momentum of gluon
1660  * is equally distributed to quark and antiquark.
1661  * Then, they have a relative transverse momentum. */
1662  px_quark[isign] = 0.5 * pgluon.px() + (isign == 0 ? 1. : -1.) * qx;
1663  py_quark[isign] = 0.5 * pgluon.py() + (isign == 0 ? 1. : -1.) * qy;
1664  pz_quark[isign] = 0.5 * pgluon.pz();
1665  e_quark[isign] =
1666  std::sqrt(mass * mass + px_quark[isign] * px_quark[isign] +
1667  py_quark[isign] * py_quark[isign] +
1668  pz_quark[isign] * pz_quark[isign]);
1669  pquark[isign] = Pythia8::Vec4(px_quark[isign], py_quark[isign],
1670  pz_quark[isign], e_quark[isign]);
1671  }
1672 
1673  /* Total energy is not conserved at this point,
1674  * but this will be cured later. */
1675  pSum += pquark[0] + pquark[1] - pgluon;
1676  // add quark and antiquark to the event record
1677  event_intermediate.append(pdgid, status, col, 0, pquark[0], mass);
1678  event_intermediate.append(-pdgid, status, 0, acol, pquark[1], mass);
1679  // then remove the gluon from the record
1680  event_intermediate.remove(iforward, iforward);
1681 
1682  logg[LPythia].debug(" gluon at iforward = ", iforward,
1683  " is splitted into ", pdgid, ",", -pdgid,
1684  " qqbar pair.");
1685  /* Increase the total number of quarks and antiquarks by 1,
1686  * as we have extra ones from a gluon. */
1687  nquark_total[iflav] += 1;
1688  nantiq_total[iflav] += 1;
1689  }
1690  }
1691  }
1692 
1693  /* The zeroth entry of event record is supposed to have the information
1694  * on the whole system. Specify the total momentum and invariant mass. */
1695  event_intermediate[0].p(pSum);
1696  event_intermediate[0].m(pSum.mCalc());
1697 
1698  return true;
1699 }
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 ...
Here is the call graph for this function:
Here is the caller graph for this function:

◆ rearrange_excess()

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

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

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

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

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

Definition at line 1701 of file stringprocess.cc.

1704  {
1705  for (int iflav = 0; iflav < 5; iflav++) {
1706  /* Find how many constituent will be in the system after
1707  * changing the flavors.
1708  * Note that nquark_total is number of constituent right after
1709  * the pythia event (with mapped incoming hadrons), while the excess
1710  * shows how many constituents we have more or less that nquark_total. */
1711  int nquark_final =
1712  nquark_total[iflav] + excess_quark[0][iflav] + excess_quark[1][iflav];
1713  /* Therefore, nquark_final should not be negative.
1714  * negative nquark_final means that it will not be possible to
1715  * find a constituent to change the flavor. */
1716  bool enough_quark = nquark_final >= 0;
1717  // If that is the case, excess of constituents will be modified
1718  if (!enough_quark) {
1719  logg[LPythia].debug(" not enough constituents with flavor ", iflav + 1,
1720  " : try to modify excess of constituents.");
1721  for (int ic = 0; ic < std::abs(nquark_final); ic++) {
1722  /* Since each incoming hadron has its own count of the excess,
1723  * it is necessary to find which one is problematic. */
1724  int ih_mod = -1;
1725  if (excess_quark[0][iflav] < 0) {
1726  ih_mod = 0;
1727  } else {
1728  ih_mod = 1;
1729  }
1730  /* Increase the excess of both quark and antiquark
1731  * with corresponding flavor (iflav + 1) by 1.
1732  * This is for conservation of the net quark number. */
1733  excess_quark[ih_mod][iflav] += 1;
1734  excess_antiq[ih_mod][iflav] += 1;
1735 
1736  /* Since incoming hadrons are mapped onto ones with
1737  * the same baryon number (or quark number),
1738  * summation of the excesses over all flavors should be zero.
1739  * Therefore, we need to find another flavor which has
1740  * a positive excess and subtract by 1. */
1741  for (int jflav = 0; jflav < 5; jflav++) {
1742  // another flavor with positive excess of constituents
1743  if (jflav != iflav && excess_quark[ih_mod][jflav] > 0) {
1744  /* Decrease the excess of both quark and antiquark
1745  * with corresponding flavor (jflav + 1) by 1. */
1746  excess_quark[ih_mod][jflav] -= 1;
1747  excess_antiq[ih_mod][jflav] -= 1;
1748  /* We only need to find one (another) flavor to subtract.
1749  * No more! */
1750  break;
1751  }
1752  }
1753  }
1754  }
1755  }
1756 }
Here is the caller graph for this function:

◆ restore_constituent()

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

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

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

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

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

Definition at line 1758 of file stringprocess.cc.

1761  {
1762  Pythia8::Vec4 pSum = event_intermediate[0].p();
1763  const double energy_init = pSum.e();
1764  logg[LPythia].debug(" initial total energy [GeV] : ", energy_init);
1765 
1766  // Total number of quarks and antiquarks, respectively.
1767  std::array<int, 5> nquark_total;
1768  std::array<int, 5> nantiq_total;
1769 
1770  /* Split a gluon into qqbar if we do not have enough constituents
1771  * to be converted in the system. */
1772  bool split_for_quark = splitting_gluon_qqbar(
1773  event_intermediate, nquark_total, nantiq_total, true, excess_quark);
1774  bool split_for_antiq = splitting_gluon_qqbar(
1775  event_intermediate, nquark_total, nantiq_total, false, excess_antiq);
1776 
1777  /* Modify excess_quark and excess_antiq if we do not have enough
1778  * constituents to be converted in the system. */
1779  if (!split_for_quark || !split_for_antiq) {
1780  rearrange_excess(nquark_total, excess_quark, excess_antiq);
1781  rearrange_excess(nantiq_total, excess_antiq, excess_quark);
1782  }
1783 
1784  // Final check if there are enough constituents.
1785  for (int iflav = 0; iflav < 5; iflav++) {
1786  if (nquark_total[iflav] + excess_quark[0][iflav] + excess_quark[1][iflav] <
1787  0) {
1788  logg[LPythia].debug("Not enough quark constituents of flavor ",
1789  iflav + 1);
1790  return false;
1791  }
1792 
1793  if (nantiq_total[iflav] + excess_antiq[0][iflav] + excess_antiq[1][iflav] <
1794  0) {
1795  logg[LPythia].debug("Not enough antiquark constituents of flavor ",
1796  -(iflav + 1));
1797  return false;
1798  }
1799  }
1800 
1801  for (int ih = 0; ih < 2; ih++) {
1802  logg[LPythia].debug(" initial excess_quark[", ih, "] = (",
1803  excess_quark[ih][0], ", ", excess_quark[ih][1], ", ",
1804  excess_quark[ih][2], ", ", excess_quark[ih][3], ", ",
1805  excess_quark[ih][4], ")");
1806  logg[LPythia].debug(" initial excess_antiq[", ih, "] = (",
1807  excess_antiq[ih][0], ", ", excess_antiq[ih][1], ", ",
1808  excess_antiq[ih][2], ", ", excess_antiq[ih][3], ", ",
1809  excess_antiq[ih][4], ")");
1810  }
1811 
1812  bool recovered_quarks = false;
1813  while (!recovered_quarks) {
1814  /* Flavor conversion begins with the most forward and backward parton
1815  * respectively for incoming_particles_[0] and incoming_particles_[1]. */
1816  std::array<bool, 2> find_forward = {true, false};
1817  const std::array<int, 5> excess_null = {0, 0, 0, 0, 0};
1818  std::array<int, 5> excess_total = excess_null;
1819 
1820  for (int ih = 0; ih < 2; ih++) { // loop over incoming hadrons
1821  int nfrag = event_intermediate.size();
1822  for (int np_end = 0; np_end < nfrag - 1; np_end++) { // constituent loop
1823  /* select the np_end-th most forward or backward parton and
1824  * change its specie.
1825  * np_end = 0 corresponds to the most forward,
1826  * np_end = 1 corresponds to the second most forward and so on. */
1827  int iforward =
1828  get_index_forward(find_forward[ih], np_end, event_intermediate);
1829  pSum -= event_intermediate[iforward].p();
1830 
1831  if (event_intermediate[iforward].id() > 0) { // quark and diquark
1832  replace_constituent(event_intermediate[iforward], excess_quark[ih]);
1833  logg[LPythia].debug(
1834  " excess_quark[", ih, "] = (", excess_quark[ih][0], ", ",
1835  excess_quark[ih][1], ", ", excess_quark[ih][2], ", ",
1836  excess_quark[ih][3], ", ", excess_quark[ih][4], ")");
1837  } else { // antiquark and anti-diquark
1838  replace_constituent(event_intermediate[iforward], excess_antiq[ih]);
1839  logg[LPythia].debug(
1840  " excess_antiq[", ih, "] = (", excess_antiq[ih][0], ", ",
1841  excess_antiq[ih][1], ", ", excess_antiq[ih][2], ", ",
1842  excess_antiq[ih][3], ", ", excess_antiq[ih][4], ")");
1843  }
1844 
1845  const int pdgid = event_intermediate[iforward].id();
1846  Pythia8::Vec4 pquark = event_intermediate[iforward].p();
1847  const double mass = pquark.mCalc();
1848 
1849  const int status = event_intermediate[iforward].status();
1850  const int color = event_intermediate[iforward].col();
1851  const int anticolor = event_intermediate[iforward].acol();
1852 
1853  pSum += pquark;
1854  event_intermediate.append(pdgid, status, color, anticolor, pquark,
1855  mass);
1856 
1857  event_intermediate.remove(iforward, iforward);
1858  /* Now the last np_end + 1 entries in event_intermediate
1859  * are np_end + 1 most forward (or backward) partons. */
1860  }
1861 
1862  // Compute the excess of net quark numbers.
1863  for (int j = 0; j < 5; j++) {
1864  excess_total[j] += (excess_quark[ih][j] - excess_antiq[ih][j]);
1865  }
1866  }
1867 
1868  /* If there is no excess of net quark numbers,
1869  * quark content is considered to be correct. */
1870  recovered_quarks = excess_total == excess_null;
1871  }
1872  logg[LPythia].debug(" valence quark contents of hadons are recovered.");
1873 
1874  logg[LPythia].debug(" current total energy [GeV] : ", pSum.e());
1875  /* rescale momenta of all partons by a constant factor
1876  * to conserve the total energy. */
1877  while (true) {
1878  if (std::abs(pSum.e() - energy_init) <=
1879  std::abs(really_small * energy_init)) {
1880  break;
1881  }
1882 
1883  double energy_current = pSum.e();
1884  double slope = 0.;
1885  for (int i = 1; i < event_intermediate.size(); i++) {
1886  slope += event_intermediate[i].pAbs2() / event_intermediate[i].e();
1887  }
1888 
1889  const double rescale_factor = 1. + (energy_init - energy_current) / slope;
1890  pSum = 0.;
1891  for (int i = 1; i < event_intermediate.size(); i++) {
1892  const double px = rescale_factor * event_intermediate[i].px();
1893  const double py = rescale_factor * event_intermediate[i].py();
1894  const double pz = rescale_factor * event_intermediate[i].pz();
1895  const double pabs = rescale_factor * event_intermediate[i].pAbs();
1896  const double mass = event_intermediate[i].m();
1897 
1898  event_intermediate[i].px(px);
1899  event_intermediate[i].py(py);
1900  event_intermediate[i].pz(pz);
1901  event_intermediate[i].e(std::sqrt(mass * mass + pabs * pabs));
1902  pSum += event_intermediate[i].p();
1903  }
1904  logg[LPythia].debug(" parton momenta are rescaled by factor of ",
1905  rescale_factor);
1906  }
1907 
1908  logg[LPythia].debug(" final total energy [GeV] : ", pSum.e());
1909  /* The zeroth entry of event record is supposed to have the information
1910  * on the whole system. Specify the total momentum and invariant mass. */
1911  event_intermediate[0].p(pSum);
1912  event_intermediate[0].m(pSum.mCalc());
1913 
1914  return true;
1915 }
bool splitting_gluon_qqbar(Pythia8::Event &event_intermediate, std::array< int, 5 > &nquark_total, std::array< int, 5 > &nantiq_total, bool sign_constituent, std::array< std::array< int, 5 >, 2 > &excess_constituent)
Take total number of quarks and check if the system has enough constituents that need to be converted...
int get_index_forward(bool find_forward, int np_end, Pythia8::Event &event)
Obtain index of the most forward or backward particle in a given PYTHIA event record.
void replace_constituent(Pythia8::Particle &particle, std::array< int, 5 > &excess_constituent)
Convert a partonic PYTHIA particle into the desired species and update the excess of constituents.
void rearrange_excess(std::array< int, 5 > &nquark_total, std::array< std::array< int, 5 >, 2 > &excess_quark, std::array< std::array< int, 5 >, 2 > &excess_antiq)
Take total number of quarks and check if the system has enough constituents that need to be converted...
Here is the call graph for this function:
Here is the caller graph for this function:

◆ compose_string_parton()

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

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

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

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

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

Definition at line 1917 of file stringprocess.cc.

1919  {
1920  Pythia8::Vec4 pSum = 0.;
1921  event_hadronize.reset();
1922 
1923  // select the most forward or backward parton.
1924  int iforward = get_index_forward(find_forward_string, 0, event_intermediate);
1925  logg[LPythia].debug("Hard non-diff: iforward = ", iforward, "(",
1926  event_intermediate[iforward].id(), ")");
1927 
1928  pSum += event_intermediate[iforward].p();
1929  event_hadronize.append(event_intermediate[iforward]);
1930 
1931  int col_to_find = event_intermediate[iforward].acol();
1932  int acol_to_find = event_intermediate[iforward].col();
1933  event_intermediate.remove(iforward, iforward);
1934  logg[LPythia].debug("Hard non-diff: event_intermediate reduces in size to ",
1935  event_intermediate.size());
1936 
1937  // trace color and anti-color indices and find corresponding partons.
1938  while (col_to_find != 0 || acol_to_find != 0) {
1939  logg[LPythia].debug(" col_to_find = ", col_to_find,
1940  ", acol_to_find = ", acol_to_find);
1941 
1942  int ifound = -1;
1943  for (int i = 1; i < event_intermediate.size(); i++) {
1944  const int pdgid = event_intermediate[i].id();
1945  bool found_col =
1946  col_to_find != 0 && col_to_find == event_intermediate[i].col();
1947  bool found_acol =
1948  acol_to_find != 0 && acol_to_find == event_intermediate[i].acol();
1949  if (found_col) {
1950  logg[LPythia].debug(" col_to_find ", col_to_find, " from i ", i, "(",
1951  pdgid, ") found");
1952  }
1953  if (found_acol) {
1954  logg[LPythia].debug(" acol_to_find ", acol_to_find, " from i ", i, "(",
1955  pdgid, ") found");
1956  }
1957 
1958  if (found_col && !found_acol) {
1959  ifound = i;
1960  col_to_find = event_intermediate[i].acol();
1961  break;
1962  } else if (!found_col && found_acol) {
1963  ifound = i;
1964  acol_to_find = event_intermediate[i].col();
1965  break;
1966  } else if (found_col && found_acol) {
1967  ifound = i;
1968  col_to_find = 0;
1969  acol_to_find = 0;
1970  break;
1971  }
1972  }
1973 
1974  if (ifound < 0) {
1975  event_intermediate.list();
1976  event_intermediate.listJunctions();
1977  event_hadronize.list();
1978  event_hadronize.listJunctions();
1979  if (col_to_find != 0) {
1980  logg[LPythia].error("No parton with col = ", col_to_find);
1981  }
1982  if (acol_to_find != 0) {
1983  logg[LPythia].error("No parton with acol = ", acol_to_find);
1984  }
1985  throw std::runtime_error("Hard string could not be identified.");
1986  } else {
1987  pSum += event_intermediate[ifound].p();
1988  // add a parton to the new event record.
1989  event_hadronize.append(event_intermediate[ifound]);
1990 
1991  // then remove from the original event record.
1992  event_intermediate.remove(ifound, ifound);
1993  logg[LPythia].debug(
1994  "Hard non-diff: event_intermediate reduces in size to ",
1995  event_intermediate.size());
1996  }
1997  }
1998 
1999  /* The zeroth entry of event record is supposed to have the information
2000  * on the whole system. Specify the total momentum and invariant mass. */
2001  event_hadronize[0].p(pSum);
2002  event_hadronize[0].m(pSum.mCalc());
2003 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ compose_string_junction()

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

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

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

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

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

Definition at line 2005 of file stringprocess.cc.

2007  {
2008  event_hadronize.reset();
2009 
2010  /* Move the first junction to the event record for hadronization
2011  * and specify color or anti-color indices to be found.
2012  * If junction kind is an odd number, it connects three quarks
2013  * to make a color-neutral baryonic configuration.
2014  * Otherwise, it connects three antiquarks
2015  * to make a color-neutral anti-baryonic configuration. */
2016  const int kind = event_intermediate.kindJunction(0);
2017  bool sign_color = kind % 2 == 1;
2018  std::vector<int> col; // color or anti-color indices of the junction legs
2019  for (int j = 0; j < 3; j++) {
2020  col.push_back(event_intermediate.colJunction(0, j));
2021  }
2022  event_hadronize.appendJunction(kind, col[0], col[1], col[2]);
2023  event_intermediate.eraseJunction(0);
2024  logg[LPythia].debug("junction (", col[0], ", ", col[1], ", ", col[2],
2025  ") with kind ", kind, " will be handled.");
2026 
2027  bool found_string = false;
2028  while (!found_string) {
2029  // trace color or anti-color indices and find corresponding partons.
2030  find_junction_leg(sign_color, col, event_intermediate, event_hadronize);
2031  found_string = true;
2032  for (unsigned int j = 0; j < col.size(); j++) {
2033  found_string = found_string && col[j] == 0;
2034  }
2035  if (!found_string) {
2036  /* if there is any leg which is not closed with parton,
2037  * look over junctions and find connected ones. */
2038  logg[LPythia].debug(" still has leg(s) unfinished.");
2039  sign_color = !sign_color;
2040  std::vector<int> junction_to_move;
2041  for (int i = 0; i < event_intermediate.sizeJunction(); i++) {
2042  const int kind_new = event_intermediate.kindJunction(i);
2043  /* If the original junction is associated with positive baryon number,
2044  * it looks for anti-junctions whose legs are connected with
2045  * anti-quarks (anti-colors in general). */
2046  if (sign_color != (kind_new % 2 == 1)) {
2047  continue;
2048  }
2049 
2050  std::array<int, 3> col_new;
2051  for (int k = 0; k < 3; k++) {
2052  col_new[k] = event_intermediate.colJunction(i, k);
2053  }
2054 
2055  int n_legs_connected = 0;
2056  // loop over remaining legs
2057  for (unsigned int j = 0; j < col.size(); j++) {
2058  if (col[j] == 0) {
2059  continue;
2060  }
2061  for (int k = 0; k < 3; k++) {
2062  if (col[j] == col_new[k]) {
2063  n_legs_connected += 1;
2064  col[j] = 0;
2065  col_new[k] = 0;
2066  }
2067  }
2068  }
2069 
2070  // specify which junction is connected to the original one.
2071  if (n_legs_connected > 0) {
2072  for (int k = 0; k < 3; k++) {
2073  if (col_new[k] != 0) {
2074  col.push_back(col_new[k]);
2075  }
2076  }
2077  logg[LPythia].debug(" junction ", i, " (",
2078  event_intermediate.colJunction(i, 0), ", ",
2079  event_intermediate.colJunction(i, 1), ", ",
2080  event_intermediate.colJunction(i, 2),
2081  ") with kind ", kind_new, " will be added.");
2082  junction_to_move.push_back(i);
2083  }
2084  }
2085 
2086  /* If there is any connected junction,
2087  * move it to the event record for hadronization. */
2088  for (unsigned int i = 0; i < junction_to_move.size(); i++) {
2089  unsigned int imove = junction_to_move[i] - i;
2090  const int kind_add = event_intermediate.kindJunction(imove);
2091  std::array<int, 3> col_add;
2092  for (int k = 0; k < 3; k++) {
2093  col_add[k] = event_intermediate.colJunction(imove, k);
2094  }
2095  // add a junction to the new event record.
2096  event_hadronize.appendJunction(kind_add, col_add[0], col_add[1],
2097  col_add[2]);
2098  // then remove from the original event record.
2099  event_intermediate.eraseJunction(imove);
2100  }
2101  }
2102  }
2103 
2104  Pythia8::Vec4 pSum = event_hadronize[0].p();
2105  find_forward_string = pSum.pz() > 0.;
2106 }
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:

◆ find_junction_leg()

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

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

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

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

Definition at line 2108 of file stringprocess.cc.

2110  {
2111  Pythia8::Vec4 pSum = event_hadronize[0].p();
2112  for (unsigned int j = 0; j < col.size(); j++) {
2113  if (col[j] == 0) {
2114  continue;
2115  }
2116  bool found_leg = false;
2117  while (!found_leg) {
2118  int ifound = -1;
2119  for (int i = 1; i < event_intermediate.size(); i++) {
2120  const int pdgid = event_intermediate[i].id();
2121  if (sign_color && col[j] == event_intermediate[i].col()) {
2122  logg[LPythia].debug(" col[", j, "] = ", col[j], " from i ", i, "(",
2123  pdgid, ") found");
2124  ifound = i;
2125  col[j] = event_intermediate[i].acol();
2126  break;
2127  } else if (!sign_color && col[j] == event_intermediate[i].acol()) {
2128  logg[LPythia].debug(" acol[", j, "] = ", col[j], " from i ", i, "(",
2129  pdgid, ") found");
2130  ifound = i;
2131  col[j] = event_intermediate[i].col();
2132  break;
2133  }
2134  }
2135 
2136  if (ifound < 0) {
2137  found_leg = true;
2138  if (event_intermediate.sizeJunction() == 0) {
2139  event_intermediate.list();
2140  event_intermediate.listJunctions();
2141  event_hadronize.list();
2142  event_hadronize.listJunctions();
2143  logg[LPythia].error("No parton with col = ", col[j],
2144  " connected with junction leg ", j);
2145  throw std::runtime_error("Hard string could not be identified.");
2146  }
2147  } else {
2148  pSum += event_intermediate[ifound].p();
2149  // add a parton to the new event record.
2150  event_hadronize.append(event_intermediate[ifound]);
2151  // then remove from the original event record.
2152  event_intermediate.remove(ifound, ifound);
2153  logg[LPythia].debug(
2154  "Hard non-diff: event_intermediate reduces in size to ",
2155  event_intermediate.size());
2156  if (col[j] == 0) {
2157  found_leg = true;
2158  }
2159  }
2160  }
2161  }
2162 
2163  /* The zeroth entry of event record is supposed to have the information
2164  * on the whole system. Specify the total momentum and invariant mass. */
2165  event_hadronize[0].p(pSum);
2166  event_hadronize[0].m(pSum.mCalc());
2167 }
Here is the caller graph for this function:

◆ get_index_forward()

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

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

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

Definition at line 991 of file stringprocess.h.

991  {
992  int iforward = 1;
993  for (int ip = 2; ip < event.size() - np_end; ip++) {
994  const double y_quark_current = event[ip].y();
995  const double y_quark_forward = event[iforward].y();
996  if ((find_forward && y_quark_current > y_quark_forward) ||
997  (!find_forward && y_quark_current < y_quark_forward)) {
998  iforward = ip;
999  }
1000  }
1001  return iforward;
1002  }
Here is the caller graph for this function:

◆ form_intermediate_particles()

void smash::StringProcess::form_intermediate_particles ( ParticleList &  intermediate_particles,
const FourVector pString,
const ThreeVector evecLong,
double  additional_xsec_supp = 1.0,
bool  find_and_scale_leading = true 
)

Set formation times and cross-section scaling factors for fragmented hadrons as described in Andersson:1983ia [5].

The input particles are expected to be in the string rest frame. This function modifies them in place: particle momenta and production vertices are boosted out of the string rest frame, formation times are assigned, and optionally leading-hadron cross-section scaling factors are recomputed.

Parameters
[in,out]intermediate_particlesFragmented hadrons to process.
[in]pStringFour-momentum of the string.
[in]evecLongUnit 3-vector along which the string is stretched.
[in]additional_xsec_suppAdditional multiplicative factor applied to cross-section scaling, e.g. coherence or medium effects.
[in]find_and_scale_leadingIf true, identify leading hadrons from valence quark or diquark endpoints and assign their cross-section scaling factors according to the leading-hadron prescription.
Precondition
intermediate_particles is not empty.
intermediate_particles contains only hadrons.

Definition at line 184 of file stringprocess.cc.

187  {
188  assert(intermediate_particles.size() > 0);
189 
190  int bstring = 0;
191  for (const ParticleData& data : intermediate_particles) {
192  bstring += data.pdgcode().baryon_number();
193  }
194 
195  const ThreeVector vstring = pString.velocity();
196  if (find_and_scale_leading) {
197  assign_all_scaling_factors(bstring, intermediate_particles, evecLong,
198  additional_xsec_supp);
199  }
200 
201  for (ParticleData& particle : intermediate_particles) {
202  const FourVector mom_in_string_restframe = particle.momentum();
203  const ThreeVector velocity_in_string_restframe =
204  mom_in_string_restframe.velocity();
205  const double gamma_string = 1.0 / particle.inverse_gamma();
206 
207  const FourVector p_com = mom_in_string_restframe.lorentz_boost(-vstring);
208  particle.set_4momentum(p_com);
209  const double tau_prod =
211  ? M_SQRT2 * particle.effective_mass() / kappa_tension_string_
213 
214  const double t_prod_string = tau_prod * gamma_string;
215 
216  FourVector fragment_position(t_prod_string,
217  t_prod_string * velocity_in_string_restframe);
218 
219  fragment_position = fragment_position.lorentz_boost(-vstring);
220 
221  particle.set_slow_formation_times(
223  soft_t_form_ * fragment_position.x0() + time_collision_);
224  }
225 }
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.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ append_intermediate_list()

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

append new particle from PYTHIA to a specific particle list

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

Definition at line 1039 of file stringprocess.h.

1040  {
1041  const std::string s = std::to_string(pdgid);
1042  PdgCode pythia_code(s);
1043  ParticleTypePtr new_type = ParticleType::try_find(pythia_code);
1044  if (new_type) {
1045  ParticleData new_particle(ParticleType::find(pythia_code));
1046  new_particle.set_4momentum(momentum);
1047  intermediate_particles.push_back(new_particle);
1048  return true;
1049  } else {
1050  // if the particle does not exist in SMASH the pythia event is rerun
1051  return false;
1052  }
1053  }
static const ParticleTypePtr try_find(PdgCode pdgcode)
Returns the ParticleTypePtr for the given pdgcode.
Definition: particletype.cc:89
Here is the call graph for this function:
Here is the caller graph for this function:

◆ convert_KaonLS()

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

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

Parameters
[out]pythia_idis PDG id to be converted.

Definition at line 1059 of file stringprocess.h.

1059  {
1060  if (pythia_id == 310 || pythia_id == 130) {
1061  pythia_id = (random::uniform_int(0, 1) == 0) ? 311 : -311;
1062  }
1063  }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ quarks_from_diquark()

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

find two quarks from a diquark.

Order does not matter.

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

Definition at line 2225 of file stringprocess.cc.

2226  {
2227  // The 4-digit pdg id should be diquark.
2228  assert((std::abs(diquark) > 1000) && (std::abs(diquark) < 5510) &&
2229  (std::abs(diquark) % 100 < 10));
2230 
2231  // The fourth digit corresponds to the spin degeneracy.
2232  deg_spin = std::abs(diquark) % 10;
2233  // Diquark (anti-diquark) is decomposed into two quarks (antiquarks).
2234  const int sign_anti = diquark > 0 ? 1 : -1;
2235 
2236  // Obtain two quarks (or antiquarks) from the first and second digit.
2237  q1 = sign_anti * (std::abs(diquark) - (std::abs(diquark) % 1000)) / 1000;
2238  q2 = sign_anti * (std::abs(diquark) % 1000 - deg_spin) / 100;
2239 }
Here is the caller graph for this function:

◆ diquark_from_quarks()

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

Construct diquark from two quarks.

Order does not matter.

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

Definition at line 2241 of file stringprocess.cc.

2241  {
2242  assert((q1 > 0 && q2 > 0) || (q1 < 0 && q2 < 0));
2243  if (std::abs(q1) < std::abs(q2)) {
2244  std::swap(q1, q2);
2245  }
2246  int diquark = std::abs(q1 * 1000 + q2 * 100);
2247  /* Adding spin degeneracy = 2S+1. For identical quarks spin cannot be 0
2248  * because of Pauli exclusion principle, so spin 1 is assumed. Otherwise
2249  * S = 0 with probability 1/4 and S = 1 with probability 3/4. */
2250  diquark += (q1 != q2 && random::uniform_int(0, 3) == 0) ? 1 : 3;
2251  return (q1 < 0) ? -diquark : diquark;
2252 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ make_string_ends()

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

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

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

Definition at line 2254 of file stringprocess.cc.

2255  {
2256  std::array<int, 3> quarks = pdg.quark_content();
2257  if (pdg.is_nucleon()) {
2258  // protons and neutrons treated seperately since single quarks is at a
2259  // different position in the PDG code
2260  if (pdg.charge() == 0) { // (anti)neutron
2261  if (random::uniform(0., 1.) < xi) {
2262  idq1 = quarks[0];
2263  idq2 = diquark_from_quarks(quarks[1], quarks[2]);
2264  } else {
2265  idq1 = quarks[1];
2266  idq2 = diquark_from_quarks(quarks[0], quarks[2]);
2267  }
2268  } else { // (anti)proton
2269  if (random::uniform(0., 1.) < xi) {
2270  idq1 = quarks[2];
2271  idq2 = diquark_from_quarks(quarks[0], quarks[1]);
2272  } else {
2273  idq1 = quarks[0];
2274  idq2 = diquark_from_quarks(quarks[1], quarks[2]);
2275  }
2276  }
2277  } else {
2278  if (pdg.is_meson()) {
2279  idq1 = quarks[1];
2280  idq2 = quarks[2];
2281  /* Some mesons with PDG id 11X are actually mixed state of uubar and
2282  * ddbar. have a random selection whether we have uubar or ddbar in this
2283  * case. */
2284  if (idq1 == 1 && idq2 == -1 && random::uniform_int(0, 1) == 0) {
2285  idq1 = 2;
2286  idq2 = -2;
2287  }
2288  } else {
2289  assert(pdg.is_baryon());
2290  // Get random quark to position 0
2291  std::swap(quarks[random::uniform_int(0, 2)], quarks[0]);
2292  idq1 = quarks[0];
2293  idq2 = diquark_from_quarks(quarks[1], quarks[2]);
2294  }
2295  }
2296  // Fulfil the convention: idq1 should be quark or anti-diquark
2297  if (idq1 < 0) {
2298  std::swap(idq1, idq2);
2299  }
2300 }
T uniform(T min, T max)
Definition: random.h:91
Here is the call graph for this function:
Here is the caller graph for this function:

◆ assign_all_scaling_factors()

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

Assign a cross section scaling factor to all outgoing particles.

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

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

Definition at line 2334 of file stringprocess.cc.

2337  {
2338  // Set each particle's cross section scaling factor to 0 first
2339  for (ParticleData& data : outgoing_particles) {
2340  data.set_cross_section_scaling_factor(0.0);
2341  }
2342  // sort outgoing particles according to the longitudinal velocity
2343  std::sort(outgoing_particles.begin(), outgoing_particles.end(),
2344  [&](ParticleData i, ParticleData j) {
2345  return i.momentum().velocity() * evecLong >
2346  j.momentum().velocity() * evecLong;
2347  });
2348  int nq1, nq2; // number of quarks at both ends of the string
2349  switch (baryon_string) {
2350  case 0:
2351  nq1 = -1;
2352  nq2 = 1;
2353  break;
2354  case 1:
2355  nq1 = 2;
2356  nq2 = 1;
2357  break;
2358  case -1:
2359  nq1 = -2;
2360  nq2 = -1;
2361  break;
2362  default:
2363  throw std::runtime_error("string is neither mesonic nor baryonic");
2364  }
2365  // Try to find nq1 on one string end and nq2 on the other string end and the
2366  // other way around. When the leading particles are close to the string
2367  // ends, the quarks are assumed to be distributed this way.
2368  std::pair<int, int> i = find_leading(nq1, nq2, outgoing_particles);
2369  std::pair<int, int> j = find_leading(nq2, nq1, outgoing_particles);
2370  if (baryon_string == 0 && i.second - i.first < j.second - j.first) {
2371  assign_scaling_factor(nq2, outgoing_particles[j.first], suppression_factor);
2372  assign_scaling_factor(nq1, outgoing_particles[j.second],
2373  suppression_factor);
2374  } else {
2375  assign_scaling_factor(nq1, outgoing_particles[i.first], suppression_factor);
2376  assign_scaling_factor(nq2, outgoing_particles[i.second],
2377  suppression_factor);
2378  }
2379 }
static std::pair< int, int > find_leading(int nq1, int nq2, ParticleList &list)
Find the leading string fragments.
static void assign_scaling_factor(int nquark, ParticleData &data, double suppression_factor)
Assign a cross section scaling factor to the given particle.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ find_leading()

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

Find the leading string fragments.

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

Parameters
[in]nq1number of valence quarks from excited hadron at forward end of the string
[in]nq2number of valence 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 2317 of file stringprocess.cc.

2318  {
2319  assert(list.size() >= 2);
2320  int end = list.size() - 1;
2321  int i1, i2;
2322  for (i1 = 0;
2323  i1 <= end && !list[i1].pdgcode().contains_enough_valence_quarks(nq1);
2324  i1++) {
2325  }
2326  for (i2 = end;
2327  i2 >= 0 && !list[i2].pdgcode().contains_enough_valence_quarks(nq2);
2328  i2--) {
2329  }
2330  std::pair<int, int> indices(i1, i2);
2331  return indices;
2332 }
Here is the caller graph for this function:

◆ assign_scaling_factor()

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

Assign a cross section scaling factor to the given particle.

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

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

Definition at line 2302 of file stringprocess.cc.

2303  {
2304  int nbaryon = data.pdgcode().baryon_number();
2305  if (nbaryon == 0) {
2306  // Mesons always get a scaling factor of 1/2 since there is never
2307  // a q-qbar pair at the end of a string so nquark is always 1
2308  data.set_cross_section_scaling_factor(0.5 * suppression_factor);
2309  } else if (data.is_baryon()) {
2310  // Leading baryons get a factor of 2/3 if they carry 2
2311  // and 1/3 if they carry 1 of the strings valence quarks
2312  data.set_cross_section_scaling_factor(suppression_factor * nquark /
2313  (3.0 * nbaryon));
2314  }
2315 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ pdg_map_for_pythia()

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

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

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

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

Definition at line 2381 of file stringprocess.cc.

2381  {
2382  PdgCode pdg_mapped(0x0);
2383 
2384  if (pdg.baryon_number() == 1) { // baryon
2385  pdg_mapped = pdg.charge() > 0 ? PdgCode(pdg::p) : PdgCode(pdg::n);
2386  } else if (pdg.baryon_number() == -1) { // antibaryon
2387  pdg_mapped = pdg.charge() < 0 ? PdgCode(-pdg::p) : PdgCode(-pdg::n);
2388  } else if (pdg.is_hadron()) { // meson
2389  if (pdg.charge() >= 0) {
2390  pdg_mapped = PdgCode(pdg::pi_p);
2391  } else {
2392  pdg_mapped = PdgCode(pdg::pi_m);
2393  }
2394  } else if (pdg.is_lepton()) { // lepton
2395  pdg_mapped = pdg.charge() < 0 ? PdgCode(0x11) : PdgCode(-0x11);
2396  } else {
2397  throw std::runtime_error("StringProcess::pdg_map_for_pythia failed.");
2398  }
2399 
2400  return pdg_mapped.get_decimal();
2401 }
constexpr int pi_p
π⁺.
constexpr int n
Neutron.
constexpr int pi_m
π⁻.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ getPPosA()

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

Definition at line 1167 of file stringprocess.h.

1167 { return PPosA_; }

◆ getPNegA()

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

Definition at line 1173 of file stringprocess.h.

1173 { return PNegA_; }

◆ getPPosB()

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

Definition at line 1179 of file stringprocess.h.

1179 { return PPosB_; }

◆ getPnegB()

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

Definition at line 1185 of file stringprocess.h.

1185 { return PNegB_; }

◆ get_massA()

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

Definition at line 1191 of file stringprocess.h.

1191 { return massA_; }

◆ get_massB()

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

Definition at line 1197 of file stringprocess.h.

1197 { return massB_; }

◆ get_sqrts()

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

Definition at line 1203 of file stringprocess.h.

1203 { return sqrtsAB_; }

◆ get_PDGs()

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

Definition at line 1209 of file stringprocess.h.

1209 { return PDGcodes_; }

◆ get_plab()

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

Definition at line 1215 of file stringprocess.h.

1215 { return plab_; }

◆ get_pcom()

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

Definition at line 1221 of file stringprocess.h.

1221 { return pcom_; }

◆ get_ucom()

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

Definition at line 1227 of file stringprocess.h.

1227 { return ucomAB_; }

◆ get_vcom()

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

Definition at line 1233 of file stringprocess.h.

1233 { return vcomAB_; }

◆ get_tcoll()

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

Definition at line 1239 of file stringprocess.h.

1239 { return time_collision_; }

◆ get_final_state()

ParticleList smash::StringProcess::get_final_state ( )
inline
Returns
final state
See also
final_state_

Definition at line 1245 of file stringprocess.h.

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

Member Data Documentation

◆ PPosA_

double smash::StringProcess::PPosA_
private

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

Definition at line 51 of file stringprocess.h.

◆ PPosB_

double smash::StringProcess::PPosB_
private

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

Definition at line 54 of file stringprocess.h.

◆ PNegA_

double smash::StringProcess::PNegA_
private

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

Definition at line 57 of file stringprocess.h.

◆ PNegB_

double smash::StringProcess::PNegB_
private

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

Definition at line 60 of file stringprocess.h.

◆ massA_

double smash::StringProcess::massA_
private

mass of incoming particle A [GeV]

Definition at line 62 of file stringprocess.h.

◆ massB_

double smash::StringProcess::massB_
private

mass of incoming particle B [GeV]

Definition at line 64 of file stringprocess.h.

◆ sqrtsAB_

double smash::StringProcess::sqrtsAB_
private

sqrt of Mandelstam variable s of collision [GeV]

Definition at line 66 of file stringprocess.h.

◆ PDGcodes_

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

PdgCodes of incoming particles.

Definition at line 68 of file stringprocess.h.

◆ plab_

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

momenta of incoming particles in the lab frame [GeV]

Definition at line 70 of file stringprocess.h.

◆ pcom_

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

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

Definition at line 72 of file stringprocess.h.

◆ ucomAB_

FourVector smash::StringProcess::ucomAB_
private

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

Definition at line 74 of file stringprocess.h.

◆ vcomAB_

ThreeVector smash::StringProcess::vcomAB_
private

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

Definition at line 76 of file stringprocess.h.

◆ evecBasisAB_

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

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

Definition at line 81 of file stringprocess.h.

◆ pmin_gluon_lightcone_

double smash::StringProcess::pmin_gluon_lightcone_
private

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

Definition at line 83 of file stringprocess.h.

◆ pow_fgluon_beta_

double smash::StringProcess::pow_fgluon_beta_
private

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

Definition at line 88 of file stringprocess.h.

◆ pow_fquark_alpha_

double smash::StringProcess::pow_fquark_alpha_
private

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

Definition at line 93 of file stringprocess.h.

◆ pow_fquark_beta_

double smash::StringProcess::pow_fquark_beta_
private

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

Definition at line 98 of file stringprocess.h.

◆ sigma_qperp_

double smash::StringProcess::sigma_qperp_
private

Transverse momentum spread of the excited strings.

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

Definition at line 104 of file stringprocess.h.

◆ stringz_a_leading_

double smash::StringProcess::stringz_a_leading_
private

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

Definition at line 109 of file stringprocess.h.

◆ stringz_b_leading_

double smash::StringProcess::stringz_b_leading_
private

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

Definition at line 114 of file stringprocess.h.

◆ stringz_a_produce_

double smash::StringProcess::stringz_a_produce_
private

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

Definition at line 119 of file stringprocess.h.

◆ stringz_b_produce_

double smash::StringProcess::stringz_b_produce_
private

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

Definition at line 124 of file stringprocess.h.

◆ strange_supp_

double smash::StringProcess::strange_supp_
private

strange quark suppression factor

Definition at line 126 of file stringprocess.h.

◆ diquark_supp_

double smash::StringProcess::diquark_supp_
private

diquark suppression factor

Definition at line 128 of file stringprocess.h.

◆ popcorn_rate_

double smash::StringProcess::popcorn_rate_
private

popcorn rate

Definition at line 130 of file stringprocess.h.

◆ damp_popcorn_

double smash::StringProcess::damp_popcorn_
private

damp popcorn meson from diquark remnant endpoint rate

Definition at line 132 of file stringprocess.h.

◆ string_sigma_T_

double smash::StringProcess::string_sigma_T_
private

transverse momentum spread in string fragmentation

Definition at line 134 of file stringprocess.h.

◆ kappa_tension_string_

double smash::StringProcess::kappa_tension_string_
private

string tension [GeV/fm]

Definition at line 136 of file stringprocess.h.

◆ time_formation_const_

double smash::StringProcess::time_formation_const_
private

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

Definition at line 138 of file stringprocess.h.

◆ soft_t_form_

double smash::StringProcess::soft_t_form_
private

factor to be multiplied to formation times in soft strings

Definition at line 140 of file stringprocess.h.

◆ time_collision_

double smash::StringProcess::time_collision_
private

time of collision in the computational frame [fm]

Definition at line 142 of file stringprocess.h.

◆ mass_dependent_formation_times_

bool smash::StringProcess::mass_dependent_formation_times_
private

Whether the formation time should depend on the mass of the fragment according to Andersson:1983ia [5] 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 154 of file stringprocess.h.

◆ prob_proton_to_d_uu_

double smash::StringProcess::prob_proton_to_d_uu_
private

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

Definition at line 159 of file stringprocess.h.

◆ separate_fragment_baryon_

bool smash::StringProcess::separate_fragment_baryon_
private

Whether to use a separate fragmentation function for leading baryons.

Definition at line 162 of file stringprocess.h.

◆ use_monash_tune_

bool smash::StringProcess::use_monash_tune_
private

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

Definition at line 168 of file stringprocess.h.

◆ additional_xsec_supp_

double smash::StringProcess::additional_xsec_supp_
private

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

Definition at line 174 of file stringprocess.h.

◆ mpi_initialization_sqrts_

std::optional<double> smash::StringProcess::mpi_initialization_sqrts_
private

Optional center-of-mass energy used to initialize MPI-capable Pythia objects.

If unset, the initialization energy is determined from the incoming hadrons.

Definition at line 181 of file stringprocess.h.

◆ pythia_settings_

std::vector<std::string> smash::StringProcess::pythia_settings_
private

Additional Pythia 8 settings passed to each internal Pythia instance.

These settings are applied after the corresponding SMASH string parameters and therefore override them if both configure the same Pythia setting.

Definition at line 190 of file stringprocess.h.

◆ final_state_

ParticleList smash::StringProcess::final_state_
private

final state array which must be accessed after the collision

Definition at line 280 of file stringprocess.h.

◆ hard_map_

pythia_map smash::StringProcess::hard_map_
private

Map object to contain the different pythia objects.

Definition at line 291 of file stringprocess.h.

◆ pythia_hadron_

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

PYTHIA object used in fragmentation.

Definition at line 294 of file stringprocess.h.

◆ pythia_sigmatot_

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

An object to compute cross-sections.

Definition at line 297 of file stringprocess.h.

◆ pythia_stringflav_

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

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

Definition at line 303 of file stringprocess.h.

◆ event_intermediate_

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

event record for intermediate partonic state in the hard string routine

Definition at line 309 of file stringprocess.h.

◆ string_parton_events_

std::vector<Pythia8::Event> smash::StringProcess::string_parton_events_
private

PYTHIA event records containing string partons to be hadronized.

Definition at line 340 of file stringprocess.h.

◆ to_cm_

Pythia8::RotBstMatrix smash::StringProcess::to_cm_

Rotation/boost matrix to transform particles to the center-of-mass frame.

Definition at line 558 of file stringprocess.h.


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