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
CoulombCorrector.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 <cmath>
18#include <complex>
19
20#include "marley/marley_utils.hh"
21#include "marley/CoulombCorrector.hh"
22#include "marley/Error.hh"
23#include "marley/Logger.hh"
24#include "marley/MassTable.hh"
25
27
28std::map< CMode, std::string > marley::CoulombCorrector
29 ::coulomb_mode_string_map_ =
30{
31 { CMode::NO_CORRECTION, "none" },
32 { CMode::FERMI_FUNCTION, "Fermi" },
33 { CMode::EMA, "EMA" },
34 { CMode::MEMA, "MEMA" },
35 { CMode::FERMI_AND_EMA, "Fermi-EMA" },
36 { CMode::FERMI_AND_MEMA, "Fermi-MEMA" },
37};
38
39namespace {
40
41 // Helper function that computes an approximate nuclear radius in natural
42 // units (1/MeV)
43 double nuclear_radius_natural_units( int A ) {
44 // First compute the approximate nuclear radius in fm
45 double R = marley_utils::r0 * std::pow( A, marley_utils::ONE_THIRD );
46
47 // Convert to natural units (MeV^(-1))
48 double R_nat = R / marley_utils::hbar_c;
49
50 return R_nat;
51 }
52
53 bool is_charged_lepton_or_antilepton( int pdg ) {
54 int abs_pdg = std::abs( pdg );
55 if ( abs_pdg != marley_utils::ELECTRON && abs_pdg != marley_utils::MUON
56 && abs_pdg != marley_utils::TAU ) return false;
57 return true;
58 }
59
60}
61
63 int pdg_d, CoulombMode mode ) : pdg_c_( pdg_c ), coulomb_mode_( mode )
64{
65 // Extract the mass number and proton number from the residue PDG code
66 Af_ = marley_utils::get_particle_A( pdg_d );
67 Zf_ = marley_utils::get_particle_Z( pdg_d );
68
69 // Get the ejectile mass from the mass table
72
73 // Do a sanity check that the ejectile is actually a charged (anti)lepton. If
74 // it's not, then set the Coulomb mode to NO_CORRECTION to prevent misuse
75 // of this object.
76 if ( !is_charged_lepton_or_antilepton(pdg_c_) ) {
77 coulomb_mode_ = CoulombMode::NO_CORRECTION;
78 }
79}
80
81// Fermi function used to calculate cross-sections
82// The form used here is based on http://en.wikipedia.org/wiki/Beta_decay
83// but rewritten for convenient use inside this class.
84// Input: beta_c (3-momentum magnitude of particle c / total energy of particle
85// c), where we assume that the ejectile (particle c) is the light product from
86// 2-2 scattering.
87double marley::CoulombCorrector::fermi_function( double beta_c ) const {
88
89 // If the PDG code for particle c is positive, then it is a
90 // negatively-charged lepton.
91 bool c_minus = ( pdg_c_ > 0 );
92
93 // Lorentz factor gamma for particle c
94 double gamma_c = std::pow( 1. - beta_c*beta_c, -marley_utils::ONE_HALF );
95
96 double s = std::sqrt( 1. - std::pow(marley_utils::alpha * Zf_, 2) );
97
98 // Estimate the nuclear radius (in MeV^(-1))
99 double rho = nuclear_radius_natural_units( Af_ );
100
101 // Sommerfeld parameter
102 double eta = marley_utils::alpha * Zf_ / beta_c;
103
104 // Adjust the value of eta if the light product from this reaction is
105 // an antilepton
106 if ( !c_minus ) eta *= -1;
107
108 // Complex variable for the gamma function
109 std::complex<double> a( s, eta );
110 double b = std::tgamma( 1 + 2*s );
111
112 return 2. * ( 1. + s ) * std::pow( 2.*beta_c*gamma_c*rho*mc_, 2.*s - 2. )
113 * std::exp( marley_utils::pi*eta ) * std::norm( marley_utils::gamma(a) )
114 / std::pow( b, 2 );
115}
116
118 const
119{
120 // Don't do anything if Coulomb corrections are switched off
121 if ( coulomb_mode_ == CoulombMode::NO_CORRECTION ) {
122 MARLEY_LOG( TRACE, "physics.coulomb" ) << "Coulomb correction factor = 1"
123 " (NO_CORRECTION mode)";
124 return 1.;
125 }
126
127 // Fermi function approach to the Coulomb correction
128 double fermi_func = fermi_function( beta_rel_cd );
129
130 // Unconditionally return the value of the Fermi function if the user
131 // has configured things this way
132 if ( coulomb_mode_ == CoulombMode::FERMI_FUNCTION ) {
133 MARLEY_LOG( TRACE, "physics.coulomb" ) << "Coulomb correction factor = "
134 << fermi_func << " (Fermi function, beta_rel = " << beta_rel_cd << ")";
135 return fermi_func;
136 }
137
138 bool use_mema = false;
139 if ( coulomb_mode_ == CoulombMode::MEMA
140 || coulomb_mode_ == CoulombMode::FERMI_AND_MEMA )
141 {
142 use_mema = true;
143 }
144
145 // Effective momentum approximation for the Coulomb correction
146 bool EMA_ok = false;
147 double factor_EMA = ema_factor( beta_rel_cd, EMA_ok, use_mema );
148
149 if ( coulomb_mode_ == CoulombMode::EMA
150 || coulomb_mode_ == CoulombMode::MEMA )
151 {
152 if ( EMA_ok ) return factor_EMA;
153 else {
154 std::string model_name( "EMA" );
155 if ( coulomb_mode_ == CoulombMode::MEMA ) model_name = "MEMA";
156 throw marley::Error( "Invalid " + model_name + " factor encountered"
157 " in marley::CoulombCorrector::coulomb_correction_factor()" );
158 }
159 }
160
161 if ( coulomb_mode_ != CoulombMode::FERMI_AND_EMA
162 && coulomb_mode_ != CoulombMode::FERMI_AND_MEMA )
163 {
164 throw marley::Error( "Unrecognized Coulomb correction mode encountered"
165 " in marley::CoulombCorrector::coulomb_correction_factor()" );
166 }
167
168 // If we've gotten this far, then we're interpolating between the Fermi
169 // function and the (M)EMA correction factor. If the (modified) effective
170 // momentum approximation is invalid because subtracting off the Coulomb
171 // potential brings the reaction below threshold, then just use the Fermi
172 // function
173 if ( !EMA_ok ) return fermi_func;
174
175 // Otherwise, choose the approach that yields the smaller correction (i.e.,
176 // the correction factor that is closest to unity).
177 double diff_Fermi = std::abs( fermi_func - 1. );
178 double diff_EMA = std::abs( factor_EMA - 1. );
179
180 double result = ( diff_Fermi < diff_EMA ) ? fermi_func : factor_EMA;
181 MARLEY_LOG( TRACE, "physics.coulomb" ) << "Coulomb correction factor = "
182 << result << " (beta_rel = " << beta_rel_cd
183 << ", Fermi = " << fermi_func << ", EMA = " << factor_EMA << ")";
184 return result;
185}
186
187// Effective momentum approximation for the Coulomb correction factor
188double marley::CoulombCorrector::ema_factor(double beta_rel_cd, bool& ok,
189 bool modified_ema) const
190{
191 // If particle c has a positive PDG code, then it is a negatively-charged
192 // lepton
193 bool minus_c = ( pdg_c_ > 0 );
194
195 // Approximate nuclear radius (MeV^(-1))
196 double R_nuc = nuclear_radius_natural_units( Af_ );
197
198 // Approximate Coulomb potential
199 double Vc = ( -3. * Zf_ * marley_utils::alpha ) / ( 2. * R_nuc );
200 // Adjust if needed for a final-state charged antilepton
201 if ( !minus_c ) Vc *= -1;
202
203 // Like the Fermi function, this approximation uses a static nuclear Coulomb
204 // potential (a sphere at the origin). Typically nuclear recoil is neglected,
205 // allowing one to compute the effective lepton momentum in the lab frame. In
206 // MARLEY's case, we do this by calculating it in the rest frame of the final
207 // nucleus ("FNR" frame). We already have the relative speed of the final
208 // nucleus and outgoing lepton, so this is easy.
209 double gamma_rel_cd = std::pow( 1. - std::pow(beta_rel_cd, 2), -0.5 );
210
211 // Check for numerical errors from the square root
212 if ( !std::isfinite(gamma_rel_cd) ) {
213 MARLEY_LOG( WARN, "physics.coulomb" ) << "Invalid beta_rel = "
214 << beta_rel_cd
215 << " encountered in marley::CoulombCorrector::ema_factor()";
216 }
217
218 // Total energy of the outgoing lepton in the FNR frame
219 double E_c_FNR = gamma_rel_cd * mc_;
220
221 // Lepton momentum in FNR frame
222 double p_c_FNR = beta_rel_cd * E_c_FNR;
223
224 // Effective FNR frame total energy
225 double E_c_FNR_eff = E_c_FNR - Vc;
226
227 // If subtracting off the Coulomb potential drops the effective energy
228 // below the lepton mass, then the expression for the effective momentum
229 // will give an imaginary value. Signal this by setting the "ok" flag to
230 // false.
231 ok = ( E_c_FNR_eff >= mc_ );
232
233 // Effective momentum in FNR frame
234 double p_c_FNR_eff = marley_utils::real_sqrt(
235 std::pow(E_c_FNR_eff, 2) - mc_*mc_ );
236
237 // Coulomb correction factor for the original EMA
238 double F_EMA = std::pow( p_c_FNR_eff / p_c_FNR, 2 );
239
240 // Coulomb correction factor for the modified EMA
241 double F_MEMA = ( p_c_FNR_eff * E_c_FNR_eff ) / ( p_c_FNR * E_c_FNR );
242
243 if ( modified_ema ) return F_MEMA;
244 else return F_EMA;
245}
246
247// Convert a string to a CoulombMode value
249 const std::string& str )
250{
251 for ( const auto& pair : coulomb_mode_string_map_ ) {
252 if ( str == pair.second ) return pair.first;
253 }
254 throw marley::Error( "The string \"" + str + "\" was not recognized"
255 " as a valid Coloumb mode setting" );
256}
257
258// Convert a CoulombMode value to a string
260 auto it = coulomb_mode_string_map_.find( mode );
261 if ( it != coulomb_mode_string_map_.end() ) return it->second;
262 else throw marley::Error( "Unrecognized CoulombMode value encountered in"
263 " marley::CoulombCorrector::string_from_coulomb_mode()" );
264}
265
266// Sets the method to use for computing Coulomb corrections. If the PDG
267// code for particle c is not a charged (anti)lepton, then ignore the
268// input and set the mode to "no correction"
270 if ( is_charged_lepton_or_antilepton(pdg_c_) ) coulomb_mode_ = mode;
271 else coulomb_mode_ = CoulombMode::NO_CORRECTION;
272}
int Zf_
Residue atomic number.
CoulombCorrector(int pdg_c, int pdg_d, CoulombMode mode=CoulombMode::FERMI_AND_MEMA)
double mc_
Ejectile mass.
double coulomb_correction_factor(double beta_rel_cd) const
static CoulombMode coulomb_mode_from_string(const std::string &str)
Convert a string to a CoulombMode value.
void set_coulomb_mode(CoulombMode mode)
Set the method for handling Coulomb corrections for this reaction.
static std::map< CoulombMode, std::string > coulomb_mode_string_map_
double ema_factor(double beta_rel_cd, bool &ok, bool modified_ema) const
int pdg_c_
Ejectile PDG code.
CoulombMode
Enumerated type used to set the method for handling Coulomb corrections for CC nuclear reactions.
int Af_
Residue mass number.
CoulombMode coulomb_mode_
The method to use when computing Coulomb corrections.
double fermi_function(double beta_c) const
Compute the Fermi function
static std::string string_from_coulomb_mode(CoulombMode mode)
Convert a CoulombMode value to a string.
Base class for all exceptions thrown by MARLEY functions.
Definition Error.hh:26
Singleton lookup table for particle and atomic masses.
Definition MassTable.hh:30
static const MassTable & Instance()
Get a const reference to the singleton instance of the MassTable.
Definition MassTable.cc:69
double get_particle_mass(int pdg_code) const
Get the mass of a particle.
Definition MassTable.cc:84