Version: SMASH-3.4
bremsstrahlungactiondilepton.cc
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (c) 2026
4  * SMASH Team
5  *
6  * GNU General Public License (GPLv3 or later)
7  *
8  */
9 
11 
12 #include "smash/constants.h"
13 #include "smash/formfactors.h"
14 #include "smash/outputinterface.h"
15 #include "smash/parametrizations.h"
16 #include "smash/particledata.h"
17 #include "smash/particletype.h"
18 #include "smash/pdgcode.h"
20 #include "smash/pow.h"
21 #include "smash/random.h"
22 
23 namespace smash {
24 
25 namespace {
26 
27 /**
28  * Helper function for calculating R_2 as defined in \iref{Weil:2013mya},
29  * eq. (42).
30  *
31  * \param[in] s Mandelstam variable s [GeV²]
32  *
33  * \return R_2(m_{inv}^2) (dimensionless)
34  */
35 double R_2_helper(const double s) {
36  const double m_pn = 2 * nucleon_mass;
37  return (s < (m_pn * m_pn)) ? 0.0 : std::sqrt(1.0 - (m_pn * m_pn) / s);
38 }
39 
40 } // namespace
41 
42 static constexpr int LScatterAction = LogArea::ScatterAction::id;
43 
45  const ParticleList &in, const double time,
46  const double hadronic_cross_section_input,
48  : ScatterAction(in[0], in[1], time),
49  reaction_type_(dilepton_brems_reaction_type_(in)),
50  hadronic_cross_section_(hadronic_cross_section_input),
51  form_factor_type_(ff_type) {}
52 
55  const ParticleList &in) {
56  if (in.size() != 2) {
58  }
59 
60  const PdgCode a = in[0].pdgcode();
61  const PdgCode b = in[1].pdgcode();
62 
63  switch (pack(a.code(), b.code())) {
64  case (pack(pdg::p, pdg::n)):
65  case (pack(pdg::n, pdg::p)):
66  return ReactionType::np;
67 
68  default:
70  }
71 }
72 
74  double reaction_cross_section) {
75  CollisionBranchPtr dummy_process = std::make_unique<CollisionBranch>(
76  incoming_particles_[0].type(), incoming_particles_[1].type(),
77  reaction_cross_section, ProcessType::BremsstrahlungDilepton);
78 
79  add_collision(std::move(dummy_process));
80 
81  // Define all outgoing particles at the end of the reaction.
82  static const ParticleTypePtr e_p_particle = &ParticleType::find(pdg::e_p);
83  static const ParticleTypePtr e_m_particle = &ParticleType::find(pdg::e_m);
84  static const ParticleTypePtr p_particle = &ParticleType::find(pdg::p);
85  static const ParticleTypePtr n_particle = &ParticleType::find(pdg::n);
86 
87  CollisionBranchList final_state_list;
88 
91  logg[LScatterAction].fatal()
92  << "Problem in " << __func__
93  << ". Looks like an unknown reaction "
94  "type for this dilepton bremsstrahlung process is present.";
95  throw std::runtime_error(
96  "Unreachable code was reached, "
97  "please check logs for details.");
98  }
99 
100  // For the 'np' reaction, the final state is 'pn e⁺e⁻' in this order.
101  final_state_list.push_back(std::make_unique<CollisionBranch>(
102  *p_particle, *n_particle, *e_p_particle, *e_m_particle,
103  reaction_cross_section, ProcessType::BremsstrahlungDilepton));
104 
105  add_processes<CollisionBranch>(std::move(final_state_list),
108 }
109 
111  const OutputsList &outputs) {
112  // Only one photon is created per event.
114  for (const auto &output : outputs) {
115  // we only care about the dilepton output, the function will take care
116  if (output->is_dilepton_output()) {
117  // we do not care about the local density
118  output->at_interaction(*this, 0.0);
119  }
120  }
121 }
122 
126  logg[LScatterAction].fatal()
127  << "Problem in " << __func__
128  << ". The function expects exactly "
129  "one process branch for the dilepton bremsstrahlung process.";
130  throw std::runtime_error(
131  "Unreachable code was reached, "
132  "please check logs for details.");
133  }
134 
135  auto *proc = collision_processes_dilepton_bremsstrahlung_[0].get();
136 
137  outgoing_particles_ = proc->particle_list();
138  process_type_ = proc->get_type();
139  FourVector interaction_point = get_interaction_point();
140 
141  assert(outgoing_particles_.size() == 4);
142  constexpr double m_p = nucleon_mass;
143  constexpr double m_n = nucleon_mass;
144  constexpr double m_e = electron_mass;
145 
146  const double M_min = 2.0 * m_e;
147  const double M_max = sqrt_s() - m_p - m_n;
148  // Check if it is possible to create a dilepton pair, i.e. M_min < M_max.
149  if (M_max <= M_min) {
150  weight_ = 0.0;
151  return;
152  } else {
153  m_inv_ = random::uniform(M_min, M_max);
154  }
155 
156  /* After fixing M, the momentum q depends on the CM energy sqrt_s.
157  * There is no lower limit beside being positive, but the upper limit is given
158  * by the kinematics of the 3-body final state.
159  */
160  const double q_min = 0.0;
161  const double q_max = pCM(sqrt_s(), m_inv_, m_p + m_n);
162 
163  // Sample q_ uniformly in [q_min, q_max] if kinematically allowed.
164  if (q_max > q_min) {
165  q_ = random::uniform(q_min, q_max);
166  } else {
167  weight_ = 0.0;
168  return;
169  }
170 
171  // The virtual photon carries 4-momentum p_ll with direction (theta, phi)
172  const double E_ll = std::sqrt(q_ * q_ + m_inv_ * m_inv_);
173 
174  Angles phitheta;
175  phitheta.distribute_isotropically();
176  const FourVector p_ll(E_ll, q_ * phitheta.threevec());
177 
178  // Calculate the recoil for the (pn)' subsystem after the collision.
179  const FourVector p_recoil = FourVector(sqrt_s(), 0.0, 0.0, 0.0) - p_ll;
180 
181  /* If the invariant mass of (pn)' is smaller than the rest masses of p and n,
182  * the sampling check fails and the function returns false, as the action is
183  * energetically not possible. Hence, set the weight to 0 and return.
184  */
186  outgoing_particles_[1])) {
187  weight_ = 0.0;
188  return;
189  }
190 
191  /* Isotropic 2-body decay in the virtual photon rest frame, then boost to
192  * pn-CM frame.
193  */
195  outgoing_particles_[3])) {
196  weight_ = 0.0;
197  return;
198  }
199 
200  weight_ =
202 
203  weight_ *= incoming_particles_[0].xsec_scaling_factor() *
204  incoming_particles_[1].xsec_scaling_factor();
205 
206  // Set positions and boost to computational frame
207  for (auto &new_particle : outgoing_particles_) {
208  new_particle.set_formation_time(time_of_execution_);
209  new_particle.set_4position(interaction_point);
210  new_particle.boost_momentum(
212  }
213 }
214 
216  const FourVector &p_parent, ParticleData &child_1, ParticleData &child_2) {
217  const double M_parent = p_parent.abs();
218  // Check whether the decay is energetically possible.
219  if (M_parent < child_1.type().mass() + child_2.type().mass()) {
220  return false;
221  }
222 
223  const double pcm =
224  pCM(M_parent, child_1.type().mass(), child_2.type().mass());
225 
226  Angles phitheta_children;
227  phitheta_children.distribute_isotropically();
228  child_1.set_4momentum(child_1.type().mass(),
229  pcm * phitheta_children.threevec());
230  child_2.set_4momentum(child_2.type().mass(),
231  -pcm * phitheta_children.threevec());
232 
233  const ThreeVector beta = p_parent.velocity();
234  child_1.boost_momentum(-beta);
235  child_2.boost_momentum(-beta);
236 
237  return true;
238 }
239 
241  const double M, const double q, const double sqrts) const {
242  const double s = sqrts * sqrts;
243  constexpr double m_p = nucleon_mass;
244  constexpr double m_n = nucleon_mass;
245  const double m_pn = m_p + m_n;
246  const double E = std::sqrt(q * q + M * M);
247 
248  // Check if the sampled point is kinematically allowed. If not, return 0.
249  if (E <= 0.0 || M <= 0.0)
250  return 0.0;
251 
252  const double sigma_bar =
253  (s - (m_pn) * (m_pn)) / (2.0 * (m_p * m_p)) * np_elastic(s);
254  const double R2_s = R_2_helper(s);
255  if (R2_s <= 0.0)
256  return 0.0;
257 
258  const double s2 = s + M * M - 2.0 * E * sqrts;
259  const double R2_s2 = R_2_helper(s2);
260  const double prefactor =
261  fine_structure * fine_structure / (6.0 * M_PI * M_PI * M_PI);
262 
263  // Factor q²/(ME³) after dE->dq substitution in diff. cross section formula.
264  return prefactor * (q * q) / (M * E * E * E) * sigma_bar * (R2_s2 / R2_s) *
266 }
267 
269  const double M) const {
270  const double rho_mass = ParticleType::find(pdg::rho_z).mass();
271  const double rho_width = ParticleType::find(pdg::rho_z).total_width(M);
272 
273  switch (form_factor_type_) {
275  return pion_em_form_factor_sqr_FF1(M * M, rho_mass, rho_width);
277  return pion_em_form_factor_sqr_FF2(M * M, rho_mass, rho_width);
279  return 1.0;
280  default:
281  using namespace std::string_literals; // NOLINT(build/namespaces)
282  throw std::logic_error("Problem in "s + __func__ +
283  ". Unknown pion form factor.");
284  }
285 }
286 
287 } // namespace smash
FourVector total_momentum_of_outgoing_particles() const
Calculate the total kinetic momentum of the outgoing particles.
Definition: action.cc:163
ParticleList outgoing_particles_
Initially this stores only the PDG codes of final-state particles.
Definition: action.h:363
const double time_of_execution_
Time at which the action is supposed to be performed (absolute time in the lab frame in fm).
Definition: action.h:369
double sqrt_s() const
Determine the total energy in the center-of-mass frame [GeV].
Definition: action.h:271
ParticleList incoming_particles_
List with data of incoming particles.
Definition: action.h:355
FourVector get_interaction_point() const
Get the interaction point.
Definition: action.cc:71
ProcessType process_type_
type of process
Definition: action.h:372
Angles provides a common interface for generating directions: i.e., two angles that should be interpr...
Definition: angles.h:59
ThreeVector threevec() const
Definition: angles.h:288
void distribute_isotropically()
Populate the object with a new direction.
Definition: angles.h:199
const ReactionType reaction_type_
Reaction process as determined from incoming particles.
double pion_em_form_factor_sq_(double m_inv) const
Returns , the squared pion electromagnetic form factor.
ReactionType
Enum for encoding bremsstrahlung process for n+p only.
const double hadronic_cross_section_
Total hadronic cross section.
void perform_dilepton_bremsstrahlung(const OutputsList &outputs)
Create the final state and write to output.
CollisionBranchList collision_processes_dilepton_bremsstrahlung_
Holds the bremsstrahlung branch.
double diff_xs_pn_dilepton_(double m_inv, double q, double sqrts) const
Fully differential cross section for .
bool sample_2body_isotropic_(const FourVector &p_parent, ParticleData &child_1, ParticleData &child_2)
Generates momenta of outgoing particles (for 2-body isotropic decays only).
static ReactionType dilepton_brems_reaction_type_(const ParticleList &in)
Determine dilepton bremsstrahlung process from incoming particle list.
double m_inv_
Sampled invariant mass of the dilepton pair.
double cross_section_dilepton_bremsstrahlung_
Total cross section of dilepton bremsstrahlung process [mb].
double weight_
Weight of the dilepton event.
double q_
Sampled 3-momentum of dilepton pair in pn-CM frame.
void generate_final_state() override
Main function: sample kinematics and compute weight for one dilepton event.
const DileptonBremsPionFormFactor form_factor_type_
Form factor type: Off, FF1, FF2.
BremsstrahlungActionDilepton(const ParticleList &in, double time, double hadronic_cross_section_input, DileptonBremsPionFormFactor ff_type)
Construct a BremsstrahlungActionDilepton object.
void add_dummy_hadronic_process(double reaction_cross_section)
Adds the hadronic process with a given cross section.
The FourVector class holds relevant values in Minkowski spacetime with (+, −, −, −) metric signature.
Definition: fourvector.h:33
double abs() const
calculate the lorentz invariant absolute value
Definition: fourvector.h:464
ThreeVector velocity() const
Get the velocity (3-vector divided by zero component).
Definition: fourvector.h:333
ParticleData contains the dynamic information of a certain particle.
Definition: particledata.h:59
void set_4momentum(const FourVector &momentum_vector)
Set the particle's 4-momentum directly.
Definition: particledata.h:177
const ParticleType & type() const
Get the type of the particle.
Definition: particledata.h:132
void boost_momentum(const ThreeVector &v)
Apply a Lorentz-boost to only the momentum.
Definition: particledata.h:352
A pointer-like interface to global references to ParticleType objects.
Definition: particletype.h:731
double total_width(const double m) const
Get the mass-dependent total width of a particle with mass m.
static const ParticleType & find(PdgCode pdgcode)
Returns the ParticleType object for the given pdgcode.
Definition: particletype.cc:99
double mass() const
Definition: particletype.h:147
PdgCode stores a Particle Data Group Particle Numbering Scheme particle type number.
Definition: pdgcode.h:108
std::int32_t code() const
Definition: pdgcode.h:319
ScatterAction is a special action which takes two incoming particles and performs a scattering,...
Definition: scatteraction.h:30
void add_collision(CollisionBranchPtr p)
Add a new collision channel.
The ThreeVector class represents a physical three-vector with the components .
Definition: threevector.h:31
Collection of useful constants that are known at compile time.
DileptonBremsPionFormFactor
Option to use form factors in dilepton bremsstrahlung as described in Shyam:2010vr .
@ FF2
Photon couples 40% directly to intrinsice quark structure of pion and 60% indirectly via meson.
@ FF1
Photon couples to pion only via meson.
@ Off
Don't use form factors, i.e. multiply by 1.
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 Section output
Section for the output information.
Definition: input_keys.h:205
double R_2_helper(const double s)
Helper function for calculating R_2 as defined in Weil:2013mya , eq.
constexpr int p
Proton.
constexpr int n
Neutron.
constexpr int rho_z
ρ⁰.
constexpr int e_p
Positron.
constexpr int e_m
Electron.
T beta(T a, T b)
Draws a random number from a beta-distribution, where probability density of is .
Definition: random.h:373
T uniform(T min, T max)
Definition: random.h:91
Definition: action.h:24
T pCM(const T sqrts, const T mass_a, const T mass_b) noexcept
Definition: kinematics.h:79
double pion_em_form_factor_sqr_FF2(double m_inv_sqr, double m_rho, double gamma_rho)
Definition: formfactors.h:179
constexpr double electron_mass
Electron mass in GeV.
Definition: constants.h:62
@ BremsstrahlungDilepton
See here for a short description.
constexpr double nucleon_mass
Nucleon mass in GeV.
Definition: constants.h:69
constexpr uint64_t pack(int32_t x, int32_t y)
Pack two int32_t into an uint64_t.
double np_elastic(double mandelstam_s)
np elastic cross section parametrization Source: Weil:2013mya , eq.
static constexpr int LScatterAction
constexpr double fine_structure
Fine-struture constant, approximately 1/137.
Definition: constants.h:106
double pion_em_form_factor_sqr_FF1(double m_inv_sqr, double m_rho, double gamma_rho)
Definition: formfactors.h:160