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
KoningDelarocheOpticalModel.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/coulomb_wavefunctions.hh"
18#include "marley/marley_utils.hh"
19
20#include "marley/HauserFeshbachDecay.hh"
21#include "marley/JSON.hh"
22#include "marley/KoningDelarocheOpticalModel.hh"
23#include "marley/Logger.hh"
24
26 int A, const marley::JSON& om_config ) : marley::CachedOpticalModel( Z, A )
27{
28 // Set the step size (fm) for numerically solving the Schrodinger equation
29 // using Numerov's method
30 get_from_json( "step_size", om_config, step_size_,
31 DEFAULT_NUMEROV_STEP_SIZE_ );
32
33 // Calculate the target mass
34 const auto& mt = marley::MassTable::Instance();
35 target_mass_ = mt.get_atomic_mass( Z, A );
36
37 // Parse the JSON input needed to set up the optical model parameters
39
40 // Initialize the spherical optical model parameters (see
41 // https://doi.org/10.1103/PhysRevC.107.014602)
42
43 int N = A_ - Z_; // Neutron number
44 double alpha = ( N - Z_ ) / static_cast< double >( A_ );
45
46 double A_to_the_one_third = std::pow( A_, 1.0/3.0 );
47
48 // Neutrons
49 v1n = om["v10"] - om["v1A"]*A_ - om["v1alpha"]*alpha; // MeV
50 v2n = om["vn20"] - om["vn2A"]*A_; // MeV^(-1)
51 v3n = om["vn30"] - om["vn3A"]*A_; // MeV^(-2)
52 v4n = om["v40"]; // MeV^(-3)
53 w1n = om["wn10"] + om["wn1A"]*A_; // MeV
54 w2n = om["w20"] + om["w2A"]*A_; // MeV
55 d1n = om["d10"] - om["d1alpha"]*alpha; // MeV
56 d2n = om["d20"] + om["d2A"]/( 1. + std::exp(
57 ( A_ - om["d2A3"]) / om["d2A2"] )
58 ); // MeV^(-1)
59 d3n = om["d30"]; // MeV
60 vso1n = om["vSO10"] + om["vSO1A"]*A_; // MeV
61 vso2n = om["vSO20"]; // MeV^(-1)
62 wso1n = om["wSO10"]; // MeV
63 wso2n = om["wSO20"]; // MeV
64 Efn = -11.2814 + 0.02646*A_; // MeV
65 Rvn = om["rV0"]*A_to_the_one_third - om["rVA"]; // fm
66 avn = om["aV0"] - om["aVA"]*A_; // fm
67 Rdn = om["rD0"]*A_to_the_one_third
68 - om["rDA"]*std::pow( A_to_the_one_third, 2 ); // fm
69 adn = om["anD0"] - om["anDA"]*A_; // fm
70 Rso_n = om["rSO0"]*A_to_the_one_third - om["rSOA"]; // fm
71 aso_n = om["aSO0"]; // fm
72
73 // Protons
74 v1p = om["v10"] - om["v1A"]*A_ + om["v1alpha"]*alpha; // MeV
75 v2p = om["vp20"] + om["vp2A"]*A_; // MeV^(-1)
76 v3p = om["vp30"] + om["vp3A"]*A_; // MeV^(-2)
77 v4p = om["v40"]; // MeV^(-3)
78 w1p = om["wp10"] + om["wp1A"]*A_; // MeV
79 w2p = om["w20"] + om["w2A"]*A_; // MeV
80 d1p = om["d10"] + om["d1alpha"]*alpha; // MeV
81 d2p = om["d20"] + om["d2A"]/( 1. + std::exp(
82 ( A_ - om["d2A3"]) / om["d2A2"] )
83 ); // MeV^(-1)
84 d3p = om["d30"]; // MeV
85 vso1p = om["vSO10"] + om["vSO1A"]*A_; // MeV
86 vso2p = om["vSO20"]; // MeV^(-1)
87 wso1p = om["wSO10"]; // MeV
88 wso2p = om["wSO20"]; // MeV
89 Efp = -8.4075 + 0.01378*A_; // MeV
90 Rvp = om["rV0"]*A_to_the_one_third - om["rVA"]; // fm
91 avp = om["aV0"] - om["aVA"]*A_; // fm
92 Rdp = om["rD0"]*A_to_the_one_third
93 - om["rDA"]*std::pow( A_to_the_one_third, 2 ); // fm
94 adp = om["apD0"] + om["apDA"]*A_; // fm
95 Rso_p = om["rSO0"]*A_to_the_one_third - om["rSOA"]; // fm
96 aso_p = om["aSO0"]; // fm
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 ); // fm
99
100 // Note that Koning and Delaroche approximated (6/5)*e^2 = 1.73 in their
101 // original paper, following a book by Wilkinson cited in their bibliography.
102 Vcbar_p = 6. * Z_ * marley_utils::e2 / ( 5. * Rc ); // MeV
103}
104
105std::complex< double >
107 double fragment_KE_lab, int fragment_pdg, int two_j, int l, int two_s,
108 int target_charge )
109{
110 update_target_mass( target_charge );
111
112 // The calculate_kinematic_variables() function will set the fragment_mass_
113 // member variable, but we need that value in advance in order to provide the
114 // total CM frame kinetic energy as input. To get around this, retrieve the
115 // fragment mass directly from the mass table instead
117 const auto& mt = marley::MassTable::Instance();
118 double m_fragment = mt.get_particle_mass( fragment_pdg );
119
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_ );
123
124 calculate_kinematic_variables( KE_tot_CM, fragment_pdg );
125 calculate_om_parameters( fragment_pdg, two_j, l, two_s );
126 return omp( r );
127}
128
129// Finish an optical model potential calculation by taking the r
130// dependence into account. Don't add in the Coulomb potential.
131std::complex< double >
132marley::KoningDelarocheOpticalModel::omp_minus_Vc( double r ) const
133{
134 double f_v = f( r, Rv, av );
135 double dfdr_d = dfdr( r, Rd, ad );
136
137 double temp_Vv = Vv * f_v;
138 double temp_Wv = Wv * f_v;
139 double temp_Wd = -4 * Wd * ad * dfdr_d;
140
141 double temp_Vso = 0;
142 double temp_Wso = 0;
143
144 if ( spin_orbit_eigenvalue != 0 ) {
145
146 double factor_so = lambda_piplus2 * dfdr( r, Rso, aso )
147 * spin_orbit_eigenvalue / r;
148
149 temp_Vso = Vso * factor_so;
150 temp_Wso = Wso * factor_so;
151 }
152
153 return std::complex<double>( -temp_Vv + temp_Vso,
154 -temp_Wv - temp_Wd + temp_Wso );
155}
156
157// Compute all of the pieces of the optical model that depend on the fragment's
158// kinetic energy in the lab frame fragment_KE_lab but not on its distance from
159// the origin r. Store them in the appropriate class members.
160void marley::KoningDelarocheOpticalModel::calculate_om_parameters(
161 int fragment_pdg, int two_j, int l, int two_s )
162{
163 // Fragment atomic, mass, and neutron numbers
164 z = marley_utils::get_particle_Z( fragment_pdg );
165 int a = marley_utils::get_particle_A( fragment_pdg );
166 int n = a - z;
167
168 // Abbreviate the variable name here for simplicity
169 const double E = fragment_KE_lab_;
170
171 // Eigenvalue of the spin-orbit operator
172 // 2*(l.s) = j*(j + 1) - l*(l + 1) - s*(s + 1)
173 // = 0.25*((2j - 2s)*(2j + 2s + 2)) - l*(l+1)
174 // (to keep the units right we take hbar = 1).
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 );
179
180
181 // Geometrical parameters
182 Rv = 0;
183 av = 0;
184 Rd = 0;
185 ad = 0;
186 Rso = 0;
187 aso = 0;
188
189 // Terms in the spherical optical model potential
190 Vv = 0;
191 Wv = 0;
192 Wd = 0;
193 Vso = 0;
194 Wso = 0;
195
196 // Energy to use when computing folded potentials
197 double E_eff = E / a;
198
199 if ( n > 0 ) {
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 );
203
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) );
208
209 Rv += n * Rvn;
210 av += n * avn;
211 Rd += n * Rdn;
212 ad += n * adn;
213 Rso += n * Rso_n;
214 aso += n * aso_n;
215
216 if ( !spin_zero ) {
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) );
221 }
222 }
223
224 if (z > 0) {
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 );
228
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) );
234
235 Rv += z * Rvp;
236 av += z * avp;
237 Rd += z * Rdp;
238 ad += z * adp;
239 Rso += z * Rso_p;
240 aso += z * aso_p;
241
242 if ( !spin_zero ) {
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));
247 }
248 }
249
250 if (a > 1) {
251 Rv /= a;
252 av /= a;
253 Rd /= a;
254 ad /= a;
255 Rso /= a;
256 aso /= a;
257
258 // Apply folding factor for composite particle spin-orbit potentials
259 if ( !spin_zero ) {
260 bool z_odd = z % 2;
261 bool n_odd = n % 2;
262 // This factor stays zero for even-even nuclides (which should all be
263 // spin-zero anyway)
264 double factor = 0.;
265 if ( z_odd && n_odd ) factor = 2.0; // odd-odd
266 else if ( z_odd != n_odd ) factor = 1.0; // even-odd
267 factor /= 2*a;
268
269 Vso *= factor;
270 Wso *= factor;
271 }
272 }
273}
274
276 double fragment_KE_lab, int fragment_pdg, int two_s, size_t l_max,
277 int target_charge )
278{
279 update_target_mass( target_charge );
280
281 // The calculate_kinematic_variables() function will set the fragment_mass_
282 // member variable, but we need that value in advance in order to provide the
283 // total CM frame kinetic energy as input. To get around this, retrieve the
284 // fragment mass directly from the mass table instead
286 const auto& mt = marley::MassTable::Instance();
287 double m_fragment = mt.get_particle_mass( fragment_pdg );
288
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_ );
292
293 calculate_kinematic_variables( KE_tot_CM, fragment_pdg );
294
295 double sum = 0.;
296 for ( size_t l = 0; l <= l_max; ++l ) {
297 int two_l = 2*l;
298 for ( int two_j = std::abs(two_l - two_s);
299 two_j <= two_l + two_s; two_j += 2 )
300 {
301 std::complex< double > S = s_matrix_element( fragment_pdg, two_j,
302 l, two_s );
303 sum += ( two_j + 1 ) * ( 1. - S.real() );
304 }
305 }
306
307 // Compute the cross section in natural units (MeV^(-2))
308 double xs = marley_utils::two_pi * sum / ( (two_s + 1)
309 * CM_frame_momentum_squared_ );
310 return xs;
311}
312
313double marley::KoningDelarocheOpticalModel::compute_transmission_coefficient(
314 double total_KE_CM, int fragment_pdg, int two_j, int l, int two_s,
315 int target_charge )
316{
317 if ( total_KE_CM <= 0. ) return 0.;
318 update_target_mass( target_charge );
319 calculate_kinematic_variables( total_KE_CM, fragment_pdg );
320
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";
324
325 std::complex< double > S = s_matrix_element( fragment_pdg, two_j, l, two_s );
326
327 // Guard against ±inf or NaN values that can occur in edge cases when the
328 // Coulomb wavefunctions get huge, e.g., for low-energy alpha emission.
329 // Numerical precision problems can lead to wrong answers, such as S == (inf,
330 // 0) instead of the correct (1, 0).
331 bool S_is_finite = std::isfinite( S.real() ) && std::isfinite( S.imag() );
332 // If we have a ±inf or NaN in one of the components of S, then set the
333 // transmission coefficient to zero
334 if ( !S_is_finite ) return 0.;
335
336 // To guard against numerical issues that can make the norm of the S-matrix
337 // element creep above unity, explicitly enforce that it lies on the interval
338 // [0, 1].
339 // TODO: revisit this, perhaps add a warning message?
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';
343 }
344 norm_S = std::min( 1., std::max(0., norm_S) );
345
346 double T = 1.0 - norm_S;
347 MARLEY_LOG( TRACE, "physics.opticalmodel" ) << "KD OMP: S = (" << S.real()
348 << ", " << S.imag() << "), T = " << T;
349 // We can now compute the transmission coefficient in the usual way
350 return T;
351}
352
353std::complex< double >
354marley::KoningDelarocheOpticalModel::s_matrix_element( int fragment_pdg,
355 int two_j, int l, int two_s )
356{
357 // Update the optical model parameters stored in this object for the
358 // given fragment, energy, and angular momenta
359 calculate_om_parameters( fragment_pdg, two_j, l, two_s );
360
361 double step_size2_over_twelve = std::pow( step_size_, 2 ) / 12.0;
362
363 std::complex< double > u1 = 0, u2 = 0;
364
365 std::complex< double > a_n_minus_two;
366
367 // a(r) really blows up at the origin for the optical model potential, but
368 // we're saved by the boundary condition that u(0) = 0. We just need
369 // something finite here, but we might as well make it zero.
370 std::complex< double > a_n_minus_one = 0;
371 std::complex< double > a_n = a(step_size_, l);
372
373 std::complex< double > u_n_minus_two;
374 // Boundary condition that the wavefunction vanishes at the origin (the
375 // optical model potential blows up at r = 0)
376 std::complex< double > u_n_minus_one = 0;
377
378 // Asymptotic approximation for a regular potential (see J. Thijssen,
379 // Computational Physics, p. 20 for details). We really just need something
380 // finite and nonzero here, since our specific choice only determines the
381 // overall normalization, which isn't important for determining the
382 // transmission coefficients.
383 std::complex< double > u_n = std::pow( step_size_, l + 1 );
384
385 // Optical model potential with and without the Coulomb potential included
386 std::complex< double > U, U_minus_Vc;
387
388 double r = step_size_;
389 do {
390 r += step_size_;
391 a_n_minus_two = a_n_minus_one;
392 a_n_minus_one = a_n;
393
394 U_minus_Vc = omp_minus_Vc( r ),
395 U = U_minus_Vc + Vc( r, Rc, z, Z_ );
396 a_n = a( r, l, U );
397
398 u_n_minus_two = u_n_minus_one;
399 u_n_minus_one = u_n;
400
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 );
404 }
405 while ( std::abs(U_minus_Vc) > MATCHING_RADIUS_THRESHOLD );
406
407 double r_match_1 = r;
408 u1 = u_n;
409
412 // Advance at least as far as r_max. The actual maximum value used (which
413 // will be an integer multiple of the step_size_) will be assigned to
414 // r_match_2.
415 double r_max = 1.2 * r_match_1;
416
417 do {
418 r += step_size_;
419 a_n_minus_two = a_n_minus_one;
420 a_n_minus_one = a_n;
421 a_n = a( r, l );
422
423 u_n_minus_two = u_n_minus_one;
424 u_n_minus_one = u_n;
425
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 );
429 }
430 while ( r < r_max );
431
432 double r_match_2 = r;
433 u2 = u_n;
434
435 // Coulomb (Sommerfeld) parameter
436 // Note that the relative (dimensionless) speed of the two particles
437 // is just the speed of the fragment in the lab frame
438 double beta_rel = marley_utils::real_sqrt( std::pow(fragment_KE_lab_, 2)
439 + 2.*fragment_KE_lab_*fragment_mass_ ) / ( fragment_KE_lab_
440 + fragment_mass_ );
441
442 // If beta_rel == 0, then eta blows up, so use a really small value
444 if ( beta_rel <= 0. ) beta_rel = 1e-8;
445
446 double eta = Z_ * z * marley_utils::alpha / beta_rel;
447
448 // Compute the Coulomb wavefunctions at the matching radii
449 std::complex< double > Hplus1, Hminus1, Hplus2, Hminus2;
450
451 // Fragment's CM frame wavenumber
452 double k = marley_utils::real_sqrt( CM_frame_momentum_squared_ )
453 / marley_utils::hbar_c;
454
455 Hplus1 = coulomb_H_plus( l, eta, k*r_match_1 );
456
457 // H+ and H- are complex conjugates of each other
458 Hminus1 = std::conj( Hplus1 );
459
460 Hplus2 = coulomb_H_plus( l, eta, k*r_match_2 );
461 Hminus2 = std::conj( Hplus2 );
462
463 // Compute the S matrix element using the radial wavefunction
464 // evaluated at the two matching radii
465 std::complex< double > S = ( u1*Hminus2 - u2*Hminus1 )
466 / ( u1*Hplus2 - u2*Hplus1 );
467 return S;
468}
469
470// Version of Schrodinger equation terms with the optical model potential
471// U pre-computed
472std::complex< double > marley::KoningDelarocheOpticalModel::a( double r,
473 int l, std::complex< double > U ) const
474{
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;
478}
479
480// Non-derivative radial Schrödinger equation terms to use for computing
481// transmission coefficients via the Numerov method
482std::complex< double > marley::KoningDelarocheOpticalModel::a( double r, int l )
483{
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;
487}
488
489// Coulomb potential for a point particle with charge q*e interacting
490// with a uniformly charged sphere with radius R and charge Q*e
491double marley::KoningDelarocheOpticalModel::Vc( double r, double R, int Q,
492 int q ) const
493{
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;
498}
499
500// Woods-Saxon shape
501double marley::KoningDelarocheOpticalModel::f( double r, double R, double a )
502 const
503{
504 return std::pow( 1. + std::exp((r - R) / a), -1 );
505}
506
507// Compute the optical model potential at radius r
508std::complex< double > marley::KoningDelarocheOpticalModel::omp( double r )
509 const
510{
511 return omp_minus_Vc( r ) + Vc( r, Rc, z, Z_ );
512}
513
514// Partial derivative with respect to r of the Woods-Saxon shape
515double marley::KoningDelarocheOpticalModel::dfdr( double r, double R, double a )
516 const
517{
518 // In the limit as r -> +-infinity, this goes to zero.
519 // We pick an upper limit for the exponent to avoid evaluating
520 // the function explicitly when r gets too large. Otherwise, C++
521 // returns NaN because the function becomes indeterminate in double
522 // precision (infinity/infinity or 0/0)
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) );
527}
528
529void marley::KoningDelarocheOpticalModel::calculate_kinematic_variables(
530 double KE_tot_CM, int fragment_pdg )
531{
532 // Store the total kinetic energy in the CM frame
533 total_CM_frame_KE_ = KE_tot_CM;
534
535 // Calculate the lab frame kinetic energy of the fragment from the
536 // total CM frame kinetic energy
537 const auto& mt = marley::MassTable::Instance();
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_ );
542
543 // Calculate the square of the CM frame 3-momentum of either particle
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_ );
548}
549
550void marley::KoningDelarocheOpticalModel::update_target_mass(
551 int target_charge )
552{
553 // Update the target mass based on its charge state
554 const auto& mt = marley::MassTable::Instance();
555 target_mass_ = mt.get_atomic_mass( Z_, A_ )
556 - target_charge*mt.get_particle_mass( marley_utils::ELECTRON );
557}
558
559void marley::KoningDelarocheOpticalModel::print( std::ostream& out ) const
560{
561 out << "----------------------------------------------------------\n";
562 out << "KD optical model for Z = " << Z_ << ", A = " << A_ << '\n';
563 out << "----------------------------------------------------------\n";
564 out << "Neutron parameters:\n\n";
565
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";
570
571 out << " w1n = " << w1n << " MeV\n";
572 out << " w2n = " << w2n << " MeV\n\n";
573
574 out << " d1n = " << d1n << " MeV\n";
575 out << " d2n = " << d2n << " MeV^{-1}\n";
576 out << " d3n = " << d3n << " MeV\n\n";
577
578 out << " vso1n = " << vso1n << " MeV\n";
579 out << " vso2n = " << vso2n << " MeV^{-1}\n\n";
580
581 out << " wso1n = " << wso1n << " MeV\n";
582 out << " wso2n = " << wso2n << " MeV\n\n";
583
584 out << " Efn = " << Efn << " MeV\n\n";
585
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";
592
593 out << "----------------------------------------------------------\n";
594 out << "Proton parameters:\n\n";
595
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";
600
601 out << " w1p = " << w1p << " MeV\n";
602 out << " w2p = " << w2p << " MeV\n\n";
603
604 out << " d1p = " << d1p << " MeV\n";
605 out << " d2p = " << d2p << " MeV^{-1}\n";
606 out << " d3p = " << d3p << " MeV\n\n";
607
608 out << " vso1p = " << vso1p << " MeV\n";
609 out << " vso2p = " << vso2p << " MeV^{-1}\n\n";
610
611 out << " wso1p = " << wso1p << " MeV\n";
612 out << " wso2p = " << wso2p << " MeV\n\n";
613
614 out << " Efp = " << Efp << " MeV\n\n";
615
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";
622
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";
628}
629
630marley::KoningDelarocheOpticalModel::ParamConfig::ParamConfig(
631 const marley::JSON& om_config )
632{
633 // Parse the JSON input needed to set up the optical model parameters
634 bool ok;
635 param_map_ = assign_from_json< std::map<std::string, double> >(
636 om_config, ok );
637
638 if ( !ok ) throw marley::Error( "Failed to parse optical model JSON"
639 " configuration" );
640}
641
642const double& marley::KoningDelarocheOpticalModel::ParamConfig::operator[](
643 const std::string& key ) const
644{
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 + "'" );
648}
Base class for all exceptions thrown by MARLEY functions.
Definition Error.hh:26
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.
Definition MassTable.cc:69
int A() const
Get the mass number.
int Z() const
Get the atomic number.