21#include "marley/Error.hh"
22#include "marley/FileManager.hh"
23#include "marley/Logger.hh"
24#include "marley/MassTable.hh"
25#include "marley/Reaction.hh"
26#include "marley/TabulatedXSec.hh"
27#include "marley/marley_utils.hh"
29marley::TabulatedXSec::TabulatedXSec(
int target_pdg,
31 double delta_ias ) : ta_( target_pdg ), proc_type_( p_type ),
32 coulomb_mode_( mode ), delta_ias_( delta_ias )
37 pdg_d_, dummy_charge );
40void marley::TabulatedXSec::add_table(
const std::string& file_name )
43 std::string full_file_name = fm.find_file( file_name );
44 if ( full_file_name.empty() ) {
45 throw marley::Error(
"Could not open the nuclear response data file \""
49 std::ifstream in_file( full_file_name );
58 unsigned num_w, num_q;
64 auto wvec = std::make_shared< std::vector<double> >();
65 auto qvec = std::make_shared< std::vector<double> >();
68 for (
unsigned iw = 0u; iw < num_w; ++iw ) {
74 for (
unsigned iq = 0u; iq < num_q; ++iq ) {
80 marley::Parity natural;
81 bool J_is_odd = (J % 2 == 1);
82 if ( J_is_odd ) natural = -1;
85 marley::Parity unnatural = -natural;
90 auto nat_resp = std::make_shared<
91 std::vector<marley::NuclearResponses> >();
93 auto unnat_resp = std::make_shared<
94 std::vector<marley::NuclearResponses> >();
97 double rcc, rll, rcl, rtVV, rtAA, rtprime;
101 while ( in_file >> rcc >> rll >> rcl >> rtVV >> rtAA >> rtprime ) {
103 if ( nat ) nat_resp->emplace_back( rcc, rll, rcl, rtVV, rtAA, rtprime );
104 else unnat_resp->emplace_back( rcc, rll, rcl, rtVV, rtAA, rtprime );
111 responses_[ nat_ml ] = ResponseTable( wvec, qvec, nat_resp );
112 responses_[ unnat_ml ] = ResponseTable( wvec, qvec, unnat_resp );
116double marley::TabulatedXSec::diff_xsec(
int pdg_a,
double KEa,
double omega,
117 double cos_theta,
const marley::TabulatedXSec::MultipoleLabel& ml )
const
119 int helicity = marley_utils::get_particle_helicity( pdg_a );
124 double ma = mt.get_particle_mass( pdg_a );
125 double mc = mt.get_particle_mass( pdg_c );
128 double Ea = KEa + ma;
129 double pa = marley_utils::real_sqrt( Ea*Ea - ma*ma );
130 double Ec = Ea - omega;
131 if ( Ec < mc )
return 0.;
133 double pc = marley_utils::real_sqrt( Ec*Ec - mc*mc );
138 if ( std::abs(cos_theta) > 1. )
return 0.;
139 double q = marley_utils::real_sqrt( pa*pa + pc*pc - 2.*pa*pc*cos_theta );
143 const auto& rt = this->responses_.at( ml );
149 double omega_eff = omega + this->delta_ias();
152 if ( omega_eff < rt.w_min() || omega_eff > rt.w_max()
153 || q < rt.q_min() || q > rt.q_max() )
return 0.;
154 auto nr = rt.interpolate( omega_eff, q );
157 double beta = pc / Ec;
158 double sin_theta2 = 1. - cos_theta*cos_theta;
160 double vcc = 1. + beta * cos_theta;
161 double vll = vcc - 2.*Ea*Ec*sin_theta2*beta*beta/q2;
162 double vcl = -2. * ( omega*vcc/q + mc*mc/Ec/q );
163 double vT = 1. - beta*cos_theta + Ea*Ec*beta*beta*sin_theta2/q2;
164 double vTprime = 2. * helicity * ( (Ea + Ec)*(1 - beta*cos_theta)/q
170 double xsec = lf * nr;
171 xsec *= 2. * marley_utils::GF2 * marley_utils::Vud2 * Ec * pc;
175 bool is_charged_current = this->is_cc();
177 if ( is_charged_current ) {
180 double mb = mt.get_atomic_mass( ta_.pdg() );
183 double Ed = omega + mb;
186 double md = marley_utils::real_sqrt( Ed*Ed - q*q );
189 double pc_dot_pd = Ec*Ed + pc*pc - pa*pc*cos_theta;
192 double beta_rel_cd = marley_utils::real_sqrt(
193 std::pow(pc_dot_pd, 2) - mc*mc*md*md ) / pc_dot_pd;
197 double FC = coul_corr.coulomb_correction_factor( beta_rel_cd );
208 std::vector< IntegralTerm >* integral_terms )
const
215 if ( integral_terms ) integral_terms->clear();
221 const auto& wvec = rt.w_grid();
222 const auto& qvec = rt.q_grid();
228 double ma = mt.get_particle_mass( pdg_a );
229 double mc = mt.get_particle_mass( pdg_c );
232 double Ea = KEa + ma;
238 size_t num_w = wvec.size();
239 size_t num_q = qvec.size();
241 size_t num_w_minus_one = num_w - 1;
242 size_t num_q_minus_one = num_q - 1;
244 double dw = ( wvec.back() - wvec.front() ) / num_w_minus_one;
245 double dq = ( qvec.back() - qvec.front() ) / num_q_minus_one;
250 for (
size_t iw = 0u; iw < num_w; ++iw ) {
255 double w_eff = wvec.at( iw );
262 if ( Ec < mc )
continue;
263 double pc = marley_utils::real_sqrt( Ec*Ec - mc*mc );
264 double pa = marley_utils::real_sqrt( Ea*Ea - ma*ma );
267 for (
size_t iq = 0u; iq < num_q; ++iq ) {
270 double q = qvec.at( iq );
273 double cos_theta = ( pa*pa + pc*pc - q*q ) / ( 2.*pa*pc );
276 double diff = this->diff_xsec( pdg_a, KEa, w, cos_theta, ml );
280 if ( diff > diff_max ) diff_max = diff;
288 if ( iq == 0u || iq == num_q_minus_one ) diff /= 2.;
294 if ( integral_terms ) {
295 double value = diff * dq * dw;
296 if ( iw == 0u || iw == num_w_minus_one ) value /= 2.;
297 integral_terms->emplace_back( w, cos_theta, value );
307 if ( iw == 0u || iw == num_w_minus_one ) w_integ /= 2.;
319double marley::TabulatedXSec::integral(
int pdg_a,
double KEa,
324 OptimizationMapKey key( pdg_a, ml );
325 auto end = optimization_map_.end();
326 auto iter = optimization_map_.find( key );
329 const auto& omv = iter->second;
330 const auto& tot = omv.tot_xsec_;
333 if ( KEa < tot.x_min() )
return 0.;
336 else if ( KEa <= tot.x_max() ) {
337 double tot_xsec = omv.tot_xsec_.evaluate( KEa );
338 diff_max = omv.max_diff_xsec_.evaluate( KEa );
342 tot_xsec = std::max( 0., tot_xsec );
343 diff_max = std::max( 0., diff_max );
351 return this->compute_integral( pdg_a, KEa, ml, diff_max );
354double marley::TabulatedXSec::integral(
int pdg_a,
double KEa )
const
357 for (
const auto& pair : responses_ ) {
359 const auto& ml = pair.first;
360 double integ_ml = this->integral( pdg_a, KEa, ml, dummy );
366void marley::TabulatedXSec::optimize(
int pdg_a,
double max_KEa ) {
367 MARLEY_LOG( INFO,
"physics.reaction.xsec" ) <<
"Optimizing CRPA cross"
368 " section up to " << max_KEa <<
" MeV";
370 for (
const auto& pair : responses_ ) {
371 const auto& ml = pair.first;
374 std::function<double(
double)> tot_xsec_func = [](double)
375 ->
double {
return 0.; };
376 std::function<double(
double)> max_diff_xsec_func = tot_xsec_func;
382 double xsec_at_max = this->integral( pdg_a, max_KEa, ml, dummy );
384 if ( xsec_at_max > 0. ) {
387 constexpr double thresh_tol = 1e-6;
391 double high_KEa = max_KEa;
395 double cur_KEa = (low_KEa + high_KEa) / 2.;
396 double xsec = this->integral( pdg_a, cur_KEa, ml, dummy );
398 if ( xsec <= 0. ) low_KEa = cur_KEa;
400 else high_KEa = cur_KEa;
403 }
while ( std::abs(high_KEa - low_KEa) > thresh_tol );
408 tot_xsec_func = [&,
this](
double KEa)
409 ->
double {
return this->integral( pdg_a, KEa, ml, dummy ); };
411 max_diff_xsec_func = [&,
this](
double KEa) ->
double {
413 this->integral( pdg_a, KEa, ml, max_diff );
418 MARLEY_LOG( DEBUG,
"physics.reaction.xsec" ) <<
"Optimizing total cross section for "
419 << ml.J_ << ml.Pi_ <<
" over KE in ["
420 << min_KEa <<
", " << max_KEa <<
"] MeV";
429 MARLEY_LOG( DEBUG,
"physics.reaction.xsec" ) <<
"Optimizing max diff for "
433 min_KEa, max_KEa, 64 );
436 OptimizationMapKey key( pdg_a, ml );
437 OptimizationMapValue value( tot_xs_cif, max_diff_xs_cif );
439 optimization_map_.emplace( std::make_pair(key, value) );
449 bool is_charged_current = this->
is_cc();
452 if ( is_charged_current ) result =
delta_ias_;
Approximates a 1D function using Chebyshev points.
Computes Coulomb correction factors for neutrino-nucleus differential cross sections.
static const FileManager & Instance()
Get a const reference to the singleton instance of the FileManager.
static const MassTable & Instance()
Get a const reference to the singleton instance of the MassTable.
static int get_ejectile_pdg(int pdg_a, ProcessType proc_type)
ProcessType
Enumerated type describing the kind of scattering process represented by a Reaction.
static void get_residue_pdg_and_charge(ProcessType proc_type, int pdg_b, int &pdg_d, int &q_d)
marley::Reaction::ProcessType proc_type_
Kind of process for which the cross section will be computed.
double delta_ias() const
Get the shift used to compute the effective energy transfer.
std::map< MultipoleLabel, ResponseTable > responses_
Tables of nuclear responses organized by multipole.
double compute_integral(int pdg_a, double KEa, const MultipoleLabel &ml, double &diff_max, std::vector< IntegralTerm > *integral_terms=nullptr) const
Helper function for integral that does the actual integration.
bool is_cc() const
Returns true if this cross section represents a CC process or false otherwise.
Simple struct representing a given multipole order, e.g., 2+.