Version: SMASH-1.5
decayaction.cc
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (c) 2014-2018
4  * SMASH Team
5  *
6  * GNU General Public License (GPLv3 or later)
7  *
8  */
9 
10 #include "smash/decayaction.h"
11 
12 #include "smash/angles.h"
13 #include "smash/decaymodes.h"
14 #include "smash/kinematics.h"
15 #include "smash/logging.h"
16 #include "smash/pdgcode.h"
18 
19 namespace smash {
20 
22  : Action({p}, time), total_width_(0.) {}
23 
24 void DecayAction::add_decays(DecayBranchList pv) {
25  add_processes<DecayBranch>(std::move(pv), decay_channels_, total_width_);
26 }
27 
28 void DecayAction::add_decay(DecayBranchPtr p) {
29  add_process<DecayBranch>(p, decay_channels_, total_width_);
30 }
31 
33  const auto &log = logger<LogArea::DecayModes>();
34  ParticleData &outgoing_a = outgoing_particles_[0];
35  ParticleData &outgoing_b = outgoing_particles_[1];
36  ParticleData &outgoing_c = outgoing_particles_[2];
37  const ParticleType &outgoing_a_type = outgoing_a.type();
38  const ParticleType &outgoing_b_type = outgoing_b.type();
39  const ParticleType &outgoing_c_type = outgoing_c.type();
40 
41  log.debug("Note: Doing 1->3 decay!");
42 
43  const double mass_a = outgoing_a_type.mass();
44  const double mass_b = outgoing_b_type.mass();
45  const double mass_c = outgoing_c_type.mass();
46  const double mass_resonance = incoming_particles_[0].effective_mass();
47 
48  // mandelstam-s limits for pairs ab and bc
49  const double s_ab_max = (mass_resonance - mass_c) * (mass_resonance - mass_c);
50  const double s_ab_min = (mass_a + mass_b) * (mass_a + mass_b);
51  const double s_bc_max = (mass_resonance - mass_a) * (mass_resonance - mass_a);
52  const double s_bc_min = (mass_b + mass_c) * (mass_b + mass_c);
53 
54  log.debug("s_ab limits: ", s_ab_min, " ", s_ab_max);
55  log.debug("s_bc limits: ", s_bc_min, " ", s_bc_max);
56 
57  /* randomly pick values for s_ab and s_bc
58  * until the pair is within the Dalitz plot */
59  double dalitz_bc_max = 0.0, dalitz_bc_min = 1.0;
60  double s_ab = 0.0, s_bc = 0.5;
61  while (s_bc > dalitz_bc_max || s_bc < dalitz_bc_min) {
62  s_ab = random::uniform(s_ab_min, s_ab_max);
63  s_bc = random::uniform(s_bc_min, s_bc_max);
64  const double e_b_rest =
65  (s_ab - mass_a * mass_a + mass_b * mass_b) / (2 * std::sqrt(s_ab));
66  const double e_c_rest =
67  (mass_resonance * mass_resonance - s_ab - mass_c * mass_c) /
68  (2 * std::sqrt(s_ab));
69  dalitz_bc_max = (e_b_rest + e_c_rest) * (e_b_rest + e_c_rest) -
70  (std::sqrt(e_b_rest * e_b_rest - mass_b * mass_b) -
71  std::sqrt(e_c_rest * e_c_rest - mass_c * mass_c)) *
72  (std::sqrt(e_b_rest * e_b_rest - mass_b * mass_b) -
73  std::sqrt(e_c_rest * e_c_rest - mass_c * mass_c));
74  dalitz_bc_min = (e_b_rest + e_c_rest) * (e_b_rest + e_c_rest) -
75  (std::sqrt(e_b_rest * e_b_rest - mass_b * mass_b) +
76  std::sqrt(e_c_rest * e_c_rest - mass_c * mass_c)) *
77  (std::sqrt(e_b_rest * e_b_rest - mass_b * mass_b) +
78  std::sqrt(e_c_rest * e_c_rest - mass_c * mass_c));
79  }
80 
81  log.debug("s_ab: ", s_ab, " s_bc: ", s_bc, " min: ", dalitz_bc_min,
82  " max: ", dalitz_bc_max);
83 
84  // Compute energy and momentum magnitude
85  const double energy_a =
86  (mass_resonance * mass_resonance + mass_a * mass_a - s_bc) /
87  (2 * mass_resonance);
88  const double energy_c =
89  (mass_resonance * mass_resonance + mass_c * mass_c - s_ab) /
90  (2 * mass_resonance);
91  const double energy_b =
92  (s_ab + s_bc - mass_a * mass_a - mass_c * mass_c) / (2 * mass_resonance);
93  const double momentum_a = std::sqrt(energy_a * energy_a - mass_a * mass_a);
94  const double momentum_c = std::sqrt(energy_c * energy_c - mass_c * mass_c);
95  const double momentum_b = std::sqrt(energy_b * energy_b - mass_b * mass_b);
96 
97  const double total_energy = sqrt_s();
98  if (std::abs(energy_a + energy_b + energy_c - total_energy) > really_small) {
99  log.warn("1->3: Ea + Eb + Ec: ", energy_a + energy_b + energy_c,
100  " Total E: ", total_energy);
101  }
102  log.debug("Calculating the angles...");
103 
104  // momentum_a direction is random
105  Angles phitheta;
106  phitheta.distribute_isotropically();
107  // This is the angle of the plane of the three decay particles
108  outgoing_a.set_4momentum(mass_a, phitheta.threevec() * momentum_a);
109 
110  // Angle between a and b
111  double theta_ab = std::acos(
112  (energy_a * energy_b - 0.5 * (s_ab - mass_a * mass_a - mass_b * mass_b)) /
113  (momentum_a * momentum_b));
114  log.debug("theta_ab: ", theta_ab, " Ea: ", energy_a, " Eb: ", energy_b,
115  " sab: ", s_ab, " pa: ", momentum_a, " pb: ", momentum_b);
116  bool phi_has_changed = phitheta.add_to_theta(theta_ab);
117  outgoing_b.set_4momentum(mass_b, phitheta.threevec() * momentum_b);
118 
119  // Angle between b and c
120  double theta_bc = std::acos(
121  (energy_b * energy_c - 0.5 * (s_bc - mass_b * mass_b - mass_c * mass_c)) /
122  (momentum_b * momentum_c));
123  log.debug("theta_bc: ", theta_bc, " Eb: ", energy_b, " Ec: ", energy_c,
124  " sbc: ", s_bc, " pb: ", momentum_b, " pc: ", momentum_c);
125  /* pass information on whether phi has changed during the last adding
126  * on to add_to_theta: */
127  phitheta.add_to_theta(theta_bc, phi_has_changed);
128  outgoing_c.set_4momentum(mass_c, phitheta.threevec() * momentum_c);
129 
130  // Momentum check
131  FourVector ptot =
132  outgoing_a.momentum() + outgoing_b.momentum() + outgoing_c.momentum();
133 
134  if (std::abs(ptot.x0() - total_energy) > really_small) {
135  log.warn("1->3 energy not conserved! Before: ", total_energy,
136  " After: ", ptot.x0());
137  }
138  if (std::abs(ptot.x1()) > really_small ||
139  std::abs(ptot.x2()) > really_small ||
140  std::abs(ptot.x3()) > really_small) {
141  log.warn("1->3 momentum check failed. Total momentum: ", ptot.threevec());
142  }
143 
144  log.debug("outgoing_a: ", outgoing_a.momentum(),
145  "\noutgoing_b: ", outgoing_b.momentum(),
146  "\noutgoing_c: ", outgoing_c.momentum());
147 }
148 
150  const auto &log = logger<LogArea::DecayModes>();
151  log.debug("Process: Resonance decay. ");
152  /* Execute a decay process for the selected particle.
153  *
154  * randomly select one of the decay modes of the particle
155  * according to their relative weights. Then decay the particle
156  * by calling function one_to_two or one_to_three.
157  */
158  const DecayBranch *proc =
159  choose_channel<DecayBranch>(decay_channels_, total_width_);
161  // set positions of the outgoing particles
162  for (auto &p : outgoing_particles_) {
163  p.set_4position(incoming_particles_[0].position());
164  }
165  process_type_ = proc->get_type();
166  L_ = proc->angular_momentum();
167  partial_width_ = proc->weight();
168 
169  switch (outgoing_particles_.size()) {
170  case 2:
172  break;
173  case 3:
174  one_to_three();
175  break;
176  default:
177  throw InvalidDecay(
178  "DecayAction::perform: Only 1->2 or 1->3 processes are supported. "
179  "Decay from 1->" +
180  std::to_string(outgoing_particles_.size()) +
181  " was requested. (PDGcode=" +
182  incoming_particles_[0].pdgcode().string() + ", mass=" +
183  std::to_string(incoming_particles_[0].effective_mass()) + ")");
184  }
185 
186  // Set formation time.
187  for (auto &p : outgoing_particles_) {
188  log.debug("particle momenta in lrf ", p);
189  // assuming decaying particles are always fully formed
190  p.set_formation_time(time_of_execution_);
191  // Boost to the computational frame
192  p.boost_momentum(-total_momentum_of_outgoing_particles().velocity());
193  log.debug("particle momenta in comp ", p);
194  }
195 }
196 
197 /* This is overridden from the Action class in order to
198  * take care of the angular momentum L_. */
199 std::pair<double, double> DecayAction::sample_masses(
200  double kinetic_energy_cm) const {
201  const ParticleType &t_a = outgoing_particles_[0].type();
202  const ParticleType &t_b = outgoing_particles_[1].type();
203 
204  // start with pole masses
205  std::pair<double, double> masses = {t_a.mass(), t_b.mass()};
206 
207  if (kinetic_energy_cm < t_a.min_mass_kinematic() + t_b.min_mass_kinematic()) {
208  const std::string reaction =
209  incoming_particles_[0].type().name() + "→" + t_a.name() + t_b.name();
211  reaction + ": not enough energy, " + std::to_string(kinetic_energy_cm) +
212  " < " + std::to_string(t_a.min_mass_kinematic()) + " + " +
213  std::to_string(t_b.min_mass_kinematic()));
214  }
215 
216  // If one of the particles is a resonance, sample its mass.
217  if (!t_a.is_stable() && t_b.is_stable()) {
218  masses.first = t_a.sample_resonance_mass(t_b.mass(), kinetic_energy_cm, L_);
219  } else if (!t_b.is_stable() && t_a.is_stable()) {
220  masses.second =
221  t_b.sample_resonance_mass(t_a.mass(), kinetic_energy_cm, L_);
222  } else if (!t_a.is_stable() && !t_b.is_stable()) {
223  // two resonances in final state
224  masses = t_a.sample_resonance_masses(t_b, kinetic_energy_cm, L_);
225  }
226 
227  return masses;
228 }
229 
230 void DecayAction::format_debug_output(std::ostream &out) const {
231  out << "Decay of " << incoming_particles_ << " to " << outgoing_particles_
232  << ", sqrt(s)=" << format(sqrt_s(), "GeV", 11, 9);
233 }
234 
235 } // namespace smash
FormattingHelper< T > format(const T &value, const char *unit, int width=-1, int precision=-1)
Acts as a stream modifier for std::ostream to output an object with an optional suffix string and wit...
Definition: logging.h:310
int angular_momentum() const
double mass() const
Definition: particletype.h:134
Thrown when DecayAction is called to perform with 0 or more than 2 entries in outgoing_particles.
Definition: decayaction.h:85
constexpr double really_small
Numerical error tolerance.
Definition: constants.h:34
double sample_resonance_mass(const double mass_stable, const double cms_energy, int L=0) const
Resonance mass sampling for 2-particle final state with one resonance (type given by &#39;this&#39;) and one ...
ProcessType process_type_
type of process
Definition: action.h:320
void add_decay(DecayBranchPtr p)
Add one new decay.
Definition: decayaction.cc:28
ThreeVector threevec() const
Definition: angles.h:268
virtual void one_to_three()
Kinematics of a 1-to-3 decay process.
Definition: decayaction.cc:32
void add_decays(DecayBranchList pv)
Add several new decays at once.
Definition: decayaction.cc:24
double x3() const
Definition: fourvector.h:302
const FourVector & momentum() const
Get the particle&#39;s 4-momentum.
Definition: particledata.h:139
double x0() const
Definition: fourvector.h:290
DecayAction(const ParticleData &p, double time)
Construct a DecayAction from a particle p.
Definition: decayaction.cc:21
DecayBranchList decay_channels_
List of possible decays.
Definition: decayaction.h:97
double total_width_
total decay width
Definition: decayaction.h:100
double weight() const
ThreeVector threevec() const
Definition: fourvector.h:306
ParticleList particle_list() const
int L_
Angular momentum of the decay.
Definition: decayaction.h:106
double x1() const
Definition: fourvector.h:294
Thrown for example when ScatterAction is called to perform with a wrong number of final-state particl...
Definition: action.h:297
bool is_stable() const
Definition: particletype.h:226
ParticleList outgoing_particles_
Initially this stores only the PDG codes of final-state particles.
Definition: action.h:311
Particle type contains the static properties of a particle species.
Definition: particletype.h:87
void set_4momentum(const FourVector &momentum_vector)
Set the particle&#39;s 4-momentum directly.
Definition: particledata.h:145
ParticleList incoming_particles_
List with data of incoming particles.
Definition: action.h:303
FourVector total_momentum_of_outgoing_particles() const
Calculate the total kinetic momentum of the outgoing particles.
Definition: action.cc:123
T uniform(T min, T max)
Definition: random.h:85
std::pair< double, double > sample_resonance_masses(const ParticleType &t2, const double cms_energy, int L=0) const
Resonance mass sampling for 2-particle final state with two resonances.
Action is the base class for a generic process that takes a number of incoming particles and transfor...
Definition: action.h:34
double x2() const
Definition: fourvector.h:298
DecayBranch is a derivative of ProcessBranch, which is used to represent decay channels.
void generate_final_state() override
Generate the final state of the decay process.
Definition: decayaction.cc:149
bool add_to_theta(const double delta)
Advance polar angle.
Definition: angles.h:224
constexpr int p
Proton.
const ParticleType & type() const
Get the type of the particle.
Definition: particledata.h:109
void sample_2body_phasespace()
Sample the full 2-body phase-space (masses, momenta, angles) in the center-of-mass frame for the fina...
Definition: action.cc:208
ProcessType get_type() const override
double min_mass_kinematic() const
The minimum mass of the resonance that is kinematically allowed.
Angles provides a common interface for generating directions: i.e., two angles that should be interpr...
Definition: angles.h:59
void distribute_isotropically()
Populate the object with a new direction.
Definition: angles.h:188
std::pair< double, double > sample_masses(double kinetic_energy_cm) const override
Sample the masses of the final particles.
Definition: decayaction.cc:199
The FourVector class holds relevant values in Minkowski spacetime with (+, −, −, −) metric signature.
Definition: fourvector.h:32
double partial_width_
partial decay width to the chosen outgoing channel
Definition: decayaction.h:103
ParticleData contains the dynamic information of a certain particle.
Definition: particledata.h:52
Definition: action.h:24
const double time_of_execution_
Time at which the action is supposed to be performed (absolute time in the lab frame in fm/c)...
Definition: action.h:317
void format_debug_output(std::ostream &out) const override
Writes information about this decay action to the out stream.
Definition: decayaction.cc:230
double sqrt_s() const
Determine the total energy in the center-of-mass frame [GeV].
Definition: action.h:265
const std::string & name() const
Definition: particletype.h:131