MARLEY (Model of Argon Reaction Low Energy Yields) v2.0.0
A Monte Carlo event generator for tens-of-MeV neutrino interactions
Loading...
Searching...
No Matches
ElectronReaction.cc
1
4//
5// This file is part of MARLEY (Model of Argon Reaction Low Energy Yields)
6//
7// MARLEY is free software: you can redistribute it and/or modify it under the
8// terms of version 3 of the GNU General Public License as published by the
9// Free Software Foundation.
10//
11// For the full text of the license please see COPYING or
12// visit http://opensource.org/licenses/GPL-3.0
13//
14// Please respect the MCnet academic usage guidelines. See GUIDELINES
15// or visit https://www.montecarlonet.org/GUIDELINES for details.
16
17#include "marley/marley_utils.hh"
18#include "marley/ElectronReaction.hh"
19#include "marley/Generator.hh"
20#include "marley/Logger.hh"
21#include "marley/hepmc3_utils.hh"
22
23namespace {
24
25 // Allowed range of cos(x)
26 constexpr double COS_MIN = -1.;
27 constexpr double COS_MAX = 1.;
28
29}
30
31marley::ElectronReaction::ElectronReaction(int pdg_a, int target_atom_pdg,
32 const std::string& source_file)
33 : Reaction( source_file ), atom_( target_atom_pdg )
34{
35 process_type_ = ProcessType::NuElectronElastic;
36
37 pdg_a_ = pdg_a;
38 pdg_b_ = marley_utils::ELECTRON;
39 pdg_c_ = get_ejectile_pdg(pdg_a_, process_type_);
40 pdg_d_ = marley_utils::ELECTRON;
41
42 // Set the description string based on the particle PDG codes
43 description_ = marley_utils::get_particle_symbol( pdg_a_ )
44 + " + " + marley_utils::get_particle_symbol( pdg_b_ );
45 description_ += " --> " + marley_utils::get_particle_symbol( pdg_c_ );
46 description_ += " + " + marley_utils::get_particle_symbol( pdg_d_ );
47
48 const auto& mt = marley::MassTable::Instance();
49 ma_ = mt.get_particle_mass( pdg_a_ );
50 mb_ = mt.get_particle_mass( pdg_b_ );
51 mc_ = mt.get_particle_mass( pdg_c_ );
52 md_ = mt.get_particle_mass( pdg_d_ );
53
54 this->set_coupling_constants();
55
56 // Compute the kinetic energy of the projectile needed
57 // for this reaction to proceed at threshold
58 KEa_threshold_ = ( std::pow(mc_ + md_, 2)
59 - std::pow(ma_ + mb_, 2) ) / ( 2.*mb_ );
60
61 MARLEY_LOG( DEBUG, "physics.reaction" ) << "ElectronReaction: "
62 << description_ << ", g1 = " << g1_ << ", g2 = " << g2_
63 << ", threshold KE = " << KEa_threshold_ << " MeV";
64}
65
66void marley::ElectronReaction::set_coupling_constants()
67{
68 if (pdg_a_ == marley_utils::ELECTRON_NEUTRINO) {
69 g1_ = marley_utils::ONE_HALF + marley_utils::sin2thetaw;
70 g2_ = marley_utils::sin2thetaw;
71 }
72 else if (pdg_a_ == marley_utils::ELECTRON_ANTINEUTRINO) {
73 g1_ = marley_utils::sin2thetaw;
74 g2_ = marley_utils::ONE_HALF + marley_utils::sin2thetaw;
75 }
76 else if (pdg_a_ == marley_utils::MUON_NEUTRINO ||
77 pdg_a_ == marley_utils::TAU_NEUTRINO)
78 {
79 g1_ = -marley_utils::ONE_HALF + marley_utils::sin2thetaw;
80 g2_ = marley_utils::sin2thetaw;
81 }
82 else if (pdg_a_ == marley_utils::MUON_ANTINEUTRINO ||
83 pdg_a_ == marley_utils::TAU_ANTINEUTRINO)
84 {
85 g1_ = marley_utils::sin2thetaw;
86 g2_ = -marley_utils::ONE_HALF + marley_utils::sin2thetaw;
87 }
88 else throw marley::Error("Unrecognized projectile PDG code "
89 + std::to_string(pdg_a_) + " encountered in marley::Electron"
90 "Reaction::set_coupling_constants()");
91}
92
93double marley::ElectronReaction::total_xs(int pdg_a, double KEa) const {
94
95 // If the cross section was requested for a different projectile,
96 // then just return zero.
97 if ( pdg_a != pdg_a_ ) return 0.;
98
99 // If we're below threshold, then just return zero
100 if ( KEa < KEa_threshold_ ) return 0.;
101
102 // If the kinetic energy is not positive, then just return zero
103 if ( KEa <= 0. ) return 0.;
104
105 // Mandelstam s (square of the total center of momentum frame energy)
106 double s = std::pow(ma_ + mb_, 2) + 2.*mb_*KEa;
107
108 // CM frame ejectile total energy
109 double Ec_cm = (s + mc_*mc_ - md_*md_) / ( 2. * std::sqrt(s) );
110
111 // Helper variables
112 double me2_over_s = md_*md_ / s;
113 double g2_squared_over_three = g2_*g2_ / 3.;
114
115 // Total cross section in natural units (MeV^(-2))
116 double xs = (4. / marley_utils::pi) * std::pow(marley_utils::GF * Ec_cm, 2)
117 * (std::pow(g1_, 2) + (g2_squared_over_three - g1_*g2_)*me2_over_s
118 + g2_squared_over_three*(1. + std::pow(me2_over_s, 2)));
119
120 // Multiply the single-electron cross section by the number of electrons
121 // present in this atom
123 xs *= atom_.Z();
124 return xs;
125}
126
128 double cos_theta_c_cm) const
129{
130 // If we're asked for the wrong projectile, then just return zero
131 if ( pdg_a != pdg_a_ ) return 0.;
132
133 // If we're below threshold, then just return zero
134 if ( KEa < KEa_threshold_ ) return 0.;
135
136 // If the kinetic energy is not positive, then just return zero
137 if ( KEa <= 0. ) return 0.;
138
139 // Mandelstam s (square of the total center of momentum frame energy)
140 double s = std::pow(ma_ + mb_, 2) + 2.*mb_*KEa;
141
142 // CM frame ejectile total energy
143 double Ec_cm = (s + mc_*mc_ - md_*md_) / ( 2. * std::sqrt(s) );
144
145 // Helper variables
146 double me2_over_s = md_*md_ / s;
147 double overall_factor = (2. / marley_utils::pi)
148 * std::pow(marley_utils::GF * Ec_cm, 2);
149 double terms = std::pow(g1_, 2) + g1_*g2_*me2_over_s*(cos_theta_c_cm - 1.)
150 + std::pow(g2_ * (1. + marley_utils::ONE_HALF*(1. - me2_over_s)
151 * (cos_theta_c_cm - 1.)), 2);
152
153 // Compute and return the cross section
154 double diff_xsec = overall_factor * terms;
155
156 // Multiply the single-electron cross section by the number of electrons
157 // present in this atom
159 diff_xsec *= atom_.Z();
160
161 return diff_xsec;
162}
163
164// Creates an event object by sampling the appropriate quantities and
165// performing kinematic calculations
166std::shared_ptr< HepMC3::GenEvent > marley::ElectronReaction::create_event(
167 int pdg_a, double KEa, marley::Generator& gen) const
168{
169 // If the projectile's PDG code doesn't match that stored in this object,
170 // complain and refuse to create an event.
171 if ( pdg_a != pdg_a_ ) throw marley::Error("Could"
172 " not create this event. The requested projectile PDG code "
173 + std::to_string(pdg_a) + " does not match the value "
174 + std::to_string(pdg_a_) + " stored in the Reaction object.");
175
176 // Also complain if we're below threshold
177 if ( KEa < KEa_threshold_ ) throw marley::Error("Could not create"
178 " this event. The kinetic energy (" + std::to_string(KEa) + " MeV)"
179 " of the projectile is below the reaction threshold of "
180 + std::to_string(KEa_threshold_) + " MeV.");
181
182 double s, Ec_cm, pc_cm, Ed_cm;
183 two_two_scatter(KEa, s, Ec_cm, pc_cm, Ed_cm);
184
185 // Compute the maximum differential cross section to use for rejection
186 // sampling. To do this, we analytically solve for the value of
187 // cos_theta_c_cm (labeled cth below) for which the derivative of the
188 // differential cross section vanishes. This is an extremum of the function
189 // and might correspond to the maximum. If cth is within the allowed angular
190 // range, then it is considered alongside the two endpoints (COS_MIN and
191 // COS_MAX), and the largest of the three values (or just the endpoint values
192 // if cth is outside the allowed range) is chosen as the maximum.
193 double me2_over_s = md_*md_ / s;
194 double B = marley_utils::ONE_HALF * std::pow(g2_*(1. - me2_over_s), 2);
195 double A = g1_*g2_*me2_over_s + g2_*g2_*(1. - me2_over_s) - B;
196 double cth = -A / B;
197
198 // Set the differential cross section to a huge negative value
199 // at cth. This value will be compared to those at the angular
200 // endpoints if cth does not lie in the allowed range. Otherwise,
201 // the correct value will replace this one.
202 double dxs_at_cth = std::numeric_limits<double>::lowest();
203
204 double max = 0.;
205 if ( cth >= COS_MIN && cth <= COS_MAX ) {
206 dxs_at_cth = this->diff_xs(pdg_a, KEa, cth);
207 }
208
209 double dxs_at_min = this->diff_xs(pdg_a, KEa, COS_MIN);
210 double dxs_at_max = this->diff_xs(pdg_a, KEa, COS_MAX);
211
212 // Find the maximum value of the differential cross section
213 max = std::max( { dxs_at_min, dxs_at_max, dxs_at_cth } );
214
215 // Sample a CM frame scattering cosine for the ejectile.
216 double cos_theta_c_cm = gen.rejection_sample(
217 [this, pdg_a, KEa](double ctheta) -> double
218 { return this->diff_xs(pdg_a, KEa, ctheta); }, COS_MIN, COS_MAX, max);
219
220 // Sample a CM frame azimuthal scattering angle (phi) uniformly on [0, 2*pi).
221 // We can do this because the differential cross section is independent of
222 // the azimuthal angle.
223 double phi_c_cm = gen.uniform_random_double(0., marley_utils::two_pi, false);
224
225 MARLEY_LOG( DEBUG, "physics.reaction" ) << "ElectronReaction::create_event:"
226 " KEa = " << KEa << " MeV, sampled cos_theta_cm = " << cos_theta_c_cm
227 << ", phi_cm = " << phi_c_cm;
228
229 // Create and return the completed event object
230 return make_event_object( KEa, pc_cm, cos_theta_c_cm, phi_c_cm, Ec_cm, Ed_cm,
231 marley_hepmc3::NUHEPMC_FINAL_STATE_STATUS );
232}
virtual double diff_xs(int pdg_a, double KEa, double cos_theta_c_cm) const
virtual std::shared_ptr< HepMC3::GenEvent > create_event(int particle_id_a, double KEa, marley::Generator &gen) const override
Create an event object for this reaction.
virtual double total_xs(int pdg_a, double KEa) const override
Compute the reaction's total cross section (MeV -2)
Base class for all exceptions thrown by MARLEY functions.
Definition Error.hh:26
The MARLEY Event generator.
Definition Generator.hh:54
double uniform_random_double(double min, double max, bool inclusive)
Sample a random number uniformly on either [min, max) or [min, max].
Definition Generator.cc:235
double rejection_sample(const std::function< double(double)> &f, double xmin, double xmax, double &fmax, double safety_factor=1.01, double max_search_tolerance=DEFAULT_REJECTION_SAMPLING_TOLERANCE_)
Sample from a given 1D probability density function f(x) on the interval [xmin, xmax] using a simple ...
Definition Generator.cc:281
static const MassTable & Instance()
Get a const reference to the singleton instance of the MassTable.
Definition MassTable.cc:69
int pdg_a_
PDG code for the projectile.
Definition Reaction.hh:142
double md_
Residue mass (MeV)
Definition Reaction.hh:154
double mc_
Ejectile mass (MeV)
Definition Reaction.hh:149
void two_two_scatter(double KEa, double &s, double &Ec_cm, double &pc_cm, double &Ed_cm) const
Helper function that handles CM frame kinematics for the reaction.
Definition Reaction.cc:226
virtual std::shared_ptr< HepMC3::GenEvent > make_event_object(double KEa, double pc_cm, double cos_theta_c_cm, double phi_c_cm, double Ec_cm, double Ed_cm, int residue_status) const
Helper function that makes an event object.
Definition Reaction.cc:247
int pdg_a() const
Get the projectile PDG code.
Definition Reaction.hh:109
double ma_
Projectile mass (MeV)
Definition Reaction.hh:147
double mb_
Target mass (MeV)
Definition Reaction.hh:148