17#include "marley/coulomb_wavefunctions.hh"
18#include "marley/marley_utils.hh"
20#include "marley/HauserFeshbachDecay.hh"
21#include "marley/JSON.hh"
22#include "marley/KoningDelarocheOpticalModel.hh"
23#include "marley/Logger.hh"
30 get_from_json(
"step_size", om_config, step_size_,
31 DEFAULT_NUMEROV_STEP_SIZE_ );
35 target_mass_ = mt.get_atomic_mass(
Z,
A );
44 double alpha = ( N - Z_ ) /
static_cast< double >( A_ );
46 double A_to_the_one_third = std::pow( A_, 1.0/3.0 );
49 v1n = om[
"v10"] - om[
"v1A"]*A_ - om[
"v1alpha"]*alpha;
50 v2n = om[
"vn20"] - om[
"vn2A"]*A_;
51 v3n = om[
"vn30"] - om[
"vn3A"]*A_;
53 w1n = om[
"wn10"] + om[
"wn1A"]*A_;
54 w2n = om[
"w20"] + om[
"w2A"]*A_;
55 d1n = om[
"d10"] - om[
"d1alpha"]*alpha;
56 d2n = om[
"d20"] + om[
"d2A"]/( 1. + std::exp(
57 ( A_ - om[
"d2A3"]) / om[
"d2A2"] )
60 vso1n = om[
"vSO10"] + om[
"vSO1A"]*A_;
64 Efn = -11.2814 + 0.02646*A_;
65 Rvn = om[
"rV0"]*A_to_the_one_third - om[
"rVA"];
66 avn = om[
"aV0"] - om[
"aVA"]*A_;
67 Rdn = om[
"rD0"]*A_to_the_one_third
68 - om[
"rDA"]*std::pow( A_to_the_one_third, 2 );
69 adn = om[
"anD0"] - om[
"anDA"]*A_;
70 Rso_n = om[
"rSO0"]*A_to_the_one_third - om[
"rSOA"];
74 v1p = om[
"v10"] - om[
"v1A"]*A_ + om[
"v1alpha"]*alpha;
75 v2p = om[
"vp20"] + om[
"vp2A"]*A_;
76 v3p = om[
"vp30"] + om[
"vp3A"]*A_;
78 w1p = om[
"wp10"] + om[
"wp1A"]*A_;
79 w2p = om[
"w20"] + om[
"w2A"]*A_;
80 d1p = om[
"d10"] + om[
"d1alpha"]*alpha;
81 d2p = om[
"d20"] + om[
"d2A"]/( 1. + std::exp(
82 ( A_ - om[
"d2A3"]) / om[
"d2A2"] )
85 vso1p = om[
"vSO10"] + om[
"vSO1A"]*A_;
89 Efp = -8.4075 + 0.01378*A_;
90 Rvp = om[
"rV0"]*A_to_the_one_third - om[
"rVA"];
91 avp = om[
"aV0"] - om[
"aVA"]*A_;
92 Rdp = om[
"rD0"]*A_to_the_one_third
93 - om[
"rDA"]*std::pow( A_to_the_one_third, 2 );
94 adp = om[
"apD0"] + om[
"apDA"]*A_;
95 Rso_p = om[
"rSO0"]*A_to_the_one_third - om[
"rSOA"];
97 Rc = om[
"rC0"]*A_to_the_one_third + om[
"rCA"]/A_to_the_one_third
98 + om[
"rCA2"]*std::pow( A_to_the_one_third, -4 );
102 Vcbar_p = 6. * Z_ * marley_utils::e2 / ( 5. * Rc );
105std::complex< double >
107 double fragment_KE_lab,
int fragment_pdg,
int two_j,
int l,
int two_s,
110 update_target_mass( target_charge );
118 double m_fragment = mt.get_particle_mass( fragment_pdg );
120 double KE_tot_CM = std::max( 0., marley_utils::real_sqrt(
121 std::pow(target_mass_ + m_fragment, 2)
122 + 2.*target_mass_*fragment_KE_lab) - m_fragment - target_mass_ );
124 calculate_kinematic_variables( KE_tot_CM, fragment_pdg );
125 calculate_om_parameters( fragment_pdg, two_j, l, two_s );
131std::complex< double >
132marley::KoningDelarocheOpticalModel::omp_minus_Vc(
double r )
const
134 double f_v = f( r, Rv, av );
135 double dfdr_d = dfdr( r, Rd, ad );
137 double temp_Vv = Vv * f_v;
138 double temp_Wv = Wv * f_v;
139 double temp_Wd = -4 * Wd * ad * dfdr_d;
144 if ( spin_orbit_eigenvalue != 0 ) {
146 double factor_so = lambda_piplus2 * dfdr( r, Rso, aso )
147 * spin_orbit_eigenvalue / r;
149 temp_Vso = Vso * factor_so;
150 temp_Wso = Wso * factor_so;
153 return std::complex<double>( -temp_Vv + temp_Vso,
154 -temp_Wv - temp_Wd + temp_Wso );
160void marley::KoningDelarocheOpticalModel::calculate_om_parameters(
161 int fragment_pdg,
int two_j,
int l,
int two_s )
164 z = marley_utils::get_particle_Z( fragment_pdg );
165 int a = marley_utils::get_particle_A( fragment_pdg );
169 const double E = fragment_KE_lab_;
175 bool spin_zero = two_s == 0;
176 if ( spin_zero ) spin_orbit_eigenvalue = 0;
177 else spin_orbit_eigenvalue = 0.25*( (two_j - two_s)
178 * (two_j + two_s + 2) ) - l*( l + 1 );
197 double E_eff = E / a;
200 double Ediff_n = E_eff - Efn;
201 double Ediff_n2 = std::pow( Ediff_n, 2 );
202 double Ediff_n3 = std::pow( Ediff_n, 3 );
204 Vv += n * v1n * ( 1. - v2n*Ediff_n + v3n*Ediff_n2 - v4n*Ediff_n3 );
205 Wv += n * w1n * Ediff_n2 / ( Ediff_n2 + std::pow(w2n, 2) );
206 Wd += n * d1n * Ediff_n2 * std::exp( -d2n * Ediff_n )
207 / ( Ediff_n2 + std::pow(d3n, 2) );
217 double Ediff_so_n = E - Efn;
218 double Ediff_so_n2 = std::pow( Ediff_so_n, 2 );
219 Vso += vso1n * std::exp( -vso2n * Ediff_so_n );
220 Wso += wso1n * Ediff_so_n2 / ( Ediff_so_n2 + std::pow(wso2n, 2) );
225 double Ediff_p = E_eff - Efp;
226 double Ediff_p2 = std::pow( Ediff_p, 2 );
227 double Ediff_p3 = std::pow( Ediff_p, 3 );
229 Vv += z * v1p * ( 1. - v2p*Ediff_p + v3p*Ediff_p2 - v4p*Ediff_p3
230 + Vcbar_p*(v2p - 2.*v3p*Ediff_p + 3.*v4p*Ediff_p2) );
231 Wv += z * w1p * Ediff_p2 / ( Ediff_p2 + std::pow(w2p, 2) );
232 Wd += z * d1p * Ediff_p2 * std::exp( -d2p * Ediff_p )
233 / ( Ediff_p2 + std::pow(d3p, 2) );
243 double Ediff_so_p = E - Efp;
244 double Ediff_so_p2 = std::pow(Ediff_so_p, 2);
245 Vso += vso1p * std::exp(-vso2p * Ediff_so_p);
246 Wso += wso1p * Ediff_so_p2 / (Ediff_so_p2 + std::pow(wso2p, 2));
265 if ( z_odd && n_odd ) factor = 2.0;
266 else if ( z_odd != n_odd ) factor = 1.0;
276 double fragment_KE_lab,
int fragment_pdg,
int two_s,
size_t l_max,
279 update_target_mass( target_charge );
287 double m_fragment = mt.get_particle_mass( fragment_pdg );
289 double KE_tot_CM = std::max( 0., marley_utils::real_sqrt(
290 std::pow(target_mass_ + m_fragment, 2)
291 + 2.*target_mass_*fragment_KE_lab) - m_fragment - target_mass_ );
293 calculate_kinematic_variables( KE_tot_CM, fragment_pdg );
296 for (
size_t l = 0; l <= l_max; ++l ) {
298 for (
int two_j = std::abs(two_l - two_s);
299 two_j <= two_l + two_s; two_j += 2 )
301 std::complex< double > S = s_matrix_element( fragment_pdg, two_j,
303 sum += ( two_j + 1 ) * ( 1. - S.real() );
308 double xs = marley_utils::two_pi * sum / ( (two_s + 1)
309 * CM_frame_momentum_squared_ );
313double marley::KoningDelarocheOpticalModel::compute_transmission_coefficient(
314 double total_KE_CM,
int fragment_pdg,
int two_j,
int l,
int two_s,
317 if ( total_KE_CM <= 0. )
return 0.;
318 update_target_mass( target_charge );
319 calculate_kinematic_variables( total_KE_CM, fragment_pdg );
321 MARLEY_LOG( DEBUG,
"physics.opticalmodel" ) <<
"KD OMP: fragment PDG "
322 << fragment_pdg <<
", 2j = " << two_j <<
", l = " << l
323 <<
", 2s = " << two_s <<
", KE_CM = " << total_KE_CM <<
" MeV";
325 std::complex< double > S = s_matrix_element( fragment_pdg, two_j, l, two_s );
331 bool S_is_finite = std::isfinite( S.real() ) && std::isfinite( S.imag() );
334 if ( !S_is_finite )
return 0.;
340 double norm_S = std::norm( S );
341 if ( norm_S < 0. || norm_S > 1.0000001 ) {
342 MARLEY_LOG( DEBUG,
"physics.opticalmodel" ) <<
"Invalid S-matrix norm = " << norm_S <<
'\n';
344 norm_S = std::min( 1., std::max(0., norm_S) );
346 double T = 1.0 - norm_S;
347 MARLEY_LOG( TRACE,
"physics.opticalmodel" ) <<
"KD OMP: S = (" << S.real()
348 <<
", " << S.imag() <<
"), T = " << T;
353std::complex< double >
354marley::KoningDelarocheOpticalModel::s_matrix_element(
int fragment_pdg,
355 int two_j,
int l,
int two_s )
359 calculate_om_parameters( fragment_pdg, two_j, l, two_s );
361 double step_size2_over_twelve = std::pow( step_size_, 2 ) / 12.0;
363 std::complex< double > u1 = 0, u2 = 0;
365 std::complex< double > a_n_minus_two;
370 std::complex< double > a_n_minus_one = 0;
371 std::complex< double > a_n = a(step_size_, l);
373 std::complex< double > u_n_minus_two;
376 std::complex< double > u_n_minus_one = 0;
383 std::complex< double > u_n = std::pow( step_size_, l + 1 );
386 std::complex< double > U, U_minus_Vc;
388 double r = step_size_;
391 a_n_minus_two = a_n_minus_one;
394 U_minus_Vc = omp_minus_Vc( r ),
395 U = U_minus_Vc + Vc( r, Rc, z, Z_ );
398 u_n_minus_two = u_n_minus_one;
401 u_n = ( (2.0 - 10*step_size2_over_twelve*a_n_minus_one)*u_n_minus_one
402 - (1.0 + step_size2_over_twelve*a_n_minus_two)*u_n_minus_two )
403 / ( 1.0 + step_size2_over_twelve*a_n );
405 while ( std::abs(U_minus_Vc) > MATCHING_RADIUS_THRESHOLD );
407 double r_match_1 = r;
415 double r_max = 1.2 * r_match_1;
419 a_n_minus_two = a_n_minus_one;
423 u_n_minus_two = u_n_minus_one;
426 u_n = ( (2.0 - 10*step_size2_over_twelve*a_n_minus_one)*u_n_minus_one
427 - (1.0 + step_size2_over_twelve*a_n_minus_two)*u_n_minus_two )
428 / ( 1.0 + step_size2_over_twelve*a_n );
432 double r_match_2 = r;
438 double beta_rel = marley_utils::real_sqrt( std::pow(fragment_KE_lab_, 2)
439 + 2.*fragment_KE_lab_*fragment_mass_ ) / ( fragment_KE_lab_
444 if ( beta_rel <= 0. ) beta_rel = 1e-8;
446 double eta = Z_ * z * marley_utils::alpha / beta_rel;
449 std::complex< double > Hplus1, Hminus1, Hplus2, Hminus2;
452 double k = marley_utils::real_sqrt( CM_frame_momentum_squared_ )
453 / marley_utils::hbar_c;
455 Hplus1 = coulomb_H_plus( l, eta, k*r_match_1 );
458 Hminus1 = std::conj( Hplus1 );
460 Hplus2 = coulomb_H_plus( l, eta, k*r_match_2 );
461 Hminus2 = std::conj( Hplus2 );
465 std::complex< double > S = ( u1*Hminus2 - u2*Hminus1 )
466 / ( u1*Hplus2 - u2*Hplus1 );
472std::complex< double > marley::KoningDelarocheOpticalModel::a(
double r,
473 int l, std::complex< double > U )
const
475 return ( -l*(l+1) / std::pow(r, 2) ) +
476 ( 1. - (U / total_CM_frame_KE_) ) * CM_frame_momentum_squared_
477 / marley_utils::hbar_c2;
482std::complex< double > marley::KoningDelarocheOpticalModel::a(
double r,
int l )
484 return ( -l*(l+1) / std::pow(r, 2) ) +
485 ( 1. - (omp(r) / total_CM_frame_KE_) ) * CM_frame_momentum_squared_
486 / marley_utils::hbar_c2;
491double marley::KoningDelarocheOpticalModel::Vc(
double r,
double R,
int Q,
494 if ( Q == 0 || q == 0 )
return 0.;
495 else if ( r < R )
return Q * q * marley_utils::e2
496 * ( 3. - std::pow(r / R, 2) ) / ( 2. * R );
497 else return Q * q * marley_utils::e2 / r;
501double marley::KoningDelarocheOpticalModel::f(
double r,
double R,
double a )
504 return std::pow( 1. + std::exp((r - R) / a), -1 );
508std::complex< double > marley::KoningDelarocheOpticalModel::omp(
double r )
511 return omp_minus_Vc( r ) + Vc( r, Rc, z, Z_ );
515double marley::KoningDelarocheOpticalModel::dfdr(
double r,
double R,
double a )
523 double exponent = ( r - R ) / a;
524 if ( std::abs(exponent) > 100. )
return 0;
525 double temp = std::exp( exponent );
526 return -temp / ( a * std::pow(1 + temp, 2) );
529void marley::KoningDelarocheOpticalModel::calculate_kinematic_variables(
530 double KE_tot_CM,
int fragment_pdg )
533 total_CM_frame_KE_ = KE_tot_CM;
538 fragment_mass_ = mt.get_particle_mass( fragment_pdg );
539 fragment_KE_lab_ = total_CM_frame_KE_ * (
540 2.*(fragment_mass_ + target_mass_) + total_CM_frame_KE_ )
541 / ( 2. * target_mass_ );
544 CM_frame_momentum_squared_ = std::pow( target_mass_, 2 ) * fragment_KE_lab_
545 * ( 2.*fragment_mass_ + fragment_KE_lab_ )
546 / ( std::pow(fragment_mass_ + target_mass_, 2)
547 + 2.*target_mass_*fragment_KE_lab_ );
550void marley::KoningDelarocheOpticalModel::update_target_mass(
555 target_mass_ = mt.get_atomic_mass( Z_, A_ )
556 - target_charge*mt.get_particle_mass( marley_utils::ELECTRON );
561 out <<
"----------------------------------------------------------\n";
562 out <<
"KD optical model for Z = " << Z_ <<
", A = " << A_ <<
'\n';
563 out <<
"----------------------------------------------------------\n";
564 out <<
"Neutron parameters:\n\n";
566 out <<
" v1n = " << v1n <<
" MeV\n";
567 out <<
" v2n = " << v2n <<
" MeV^{-1}\n";
568 out <<
" v3n = " << v3n <<
" MeV^{-2}\n";
569 out <<
" v4n = " << v4n <<
" MeV^{-3}\n\n";
571 out <<
" w1n = " << w1n <<
" MeV\n";
572 out <<
" w2n = " << w2n <<
" MeV\n\n";
574 out <<
" d1n = " << d1n <<
" MeV\n";
575 out <<
" d2n = " << d2n <<
" MeV^{-1}\n";
576 out <<
" d3n = " << d3n <<
" MeV\n\n";
578 out <<
" vso1n = " << vso1n <<
" MeV\n";
579 out <<
" vso2n = " << vso2n <<
" MeV^{-1}\n\n";
581 out <<
" wso1n = " << wso1n <<
" MeV\n";
582 out <<
" wso2n = " << wso2n <<
" MeV\n\n";
584 out <<
" Efn = " << Efn <<
" MeV\n\n";
586 out <<
" Rvn = " << Rvn <<
" fm\n";
587 out <<
" avn = " << avn <<
" fm\n";
588 out <<
" Rdn = " << Rdn <<
" fm\n";
589 out <<
" adn = " << adn <<
" fm\n";
590 out <<
" Rso_n = " << Rso_n <<
" fm\n";
591 out <<
" aso_n = " << aso_n <<
" fm\n";
593 out <<
"----------------------------------------------------------\n";
594 out <<
"Proton parameters:\n\n";
596 out <<
" v1p = " << v1p <<
" MeV\n";
597 out <<
" v2p = " << v2p <<
" MeV^{-1}\n";
598 out <<
" v3p = " << v3p <<
" MeV^{-2}\n";
599 out <<
" v4p = " << v4p <<
" MeV^{-3}\n\n";
601 out <<
" w1p = " << w1p <<
" MeV\n";
602 out <<
" w2p = " << w2p <<
" MeV\n\n";
604 out <<
" d1p = " << d1p <<
" MeV\n";
605 out <<
" d2p = " << d2p <<
" MeV^{-1}\n";
606 out <<
" d3p = " << d3p <<
" MeV\n\n";
608 out <<
" vso1p = " << vso1p <<
" MeV\n";
609 out <<
" vso2p = " << vso2p <<
" MeV^{-1}\n\n";
611 out <<
" wso1p = " << wso1p <<
" MeV\n";
612 out <<
" wso2p = " << wso2p <<
" MeV\n\n";
614 out <<
" Efp = " << Efp <<
" MeV\n\n";
616 out <<
" Rvp = " << Rvp <<
" fm\n";
617 out <<
" avp = " << avp <<
" fm\n";
618 out <<
" Rdp = " << Rdp <<
" fm\n";
619 out <<
" adp = " << adp <<
" fm\n";
620 out <<
" Rso_p = " << Rso_p <<
" fm\n";
621 out <<
" aso_p = " << aso_p <<
" fm\n\n";
623 out <<
" Rc = " << Rc <<
" fm\n";
624 out <<
" Vcbar_p = " << Vcbar_p <<
" MeV\n";
625 out <<
"----------------------------------------------------------\n";
626 out <<
" Step size = " << step_size_ <<
" fm\n";
627 out <<
"----------------------------------------------------------\n";
630marley::KoningDelarocheOpticalModel::ParamConfig::ParamConfig(
635 param_map_ = assign_from_json< std::map<std::string, double> >(
638 if ( !ok )
throw marley::Error(
"Failed to parse optical model JSON"
642const double& marley::KoningDelarocheOpticalModel::ParamConfig::operator[](
643 const std::string& key )
const
645 auto iter = param_map_.find( key );
646 if ( iter != param_map_.end() )
return iter->second;
647 throw marley::Error(
"Missing optical model parameter '" + key +
"'" );
CachedOpticalModel(int Z, int A)
Base class for all exceptions thrown by MARLEY functions.
virtual std::complex< double > optical_model_potential(double r, double fragment_KE_lab, int fragment_pdg, int two_j, int l, int two_s, int target_charge=0) override
Calculate the optical model potential (including the Coulomb potential)
KoningDelarocheOpticalModel(int Z, int A, const JSON &om_config)
virtual double total_cross_section(double fragment_KE_lab, int fragment_pdg, int two_s, size_t l_max, int target_charge=0) override
Compute the energy-averaged total cross section (MeV -2) for a nuclear fragment projectile.
virtual void print(std::ostream &out) const override
Print information about the optical model parameters.
static const MassTable & Instance()
Get a const reference to the singleton instance of the MassTable.
int A() const
Get the mass number.
int Z() const
Get the atomic number.