@@ -214,13 +214,8 @@ PhotonInteraction::PhotonInteraction(hid_t group)
214214 rgroup = open_group (group, " compton_profiles" );
215215
216216 // Read electron shell PDF and binding energies
217- tensor::Tensor<double > electron_pdf;
218- read_dataset (rgroup, " num_electrons" , electron_pdf);
219- electron_pdf /= electron_pdf.sum ();
220- electron_cdf_ = tensor::Tensor<double >(electron_pdf.shape ());
221- electron_cdf_ (0 ) = electron_pdf (0 );
222- for (int i = 1 ; i < electron_pdf.shape ()[0 ]; ++i)
223- electron_cdf_ (i) = electron_cdf_ (i - 1 ) + electron_pdf (i);
217+ read_dataset (rgroup, " num_electrons" , electron_pdf_);
218+ electron_pdf_ /= electron_pdf_.sum ();
224219 read_dataset (rgroup, " binding_energy" , binding_energy_);
225220
226221 // Read Compton profiles
@@ -428,25 +423,13 @@ void PhotonInteraction::compton_scatter(double alpha, bool doppler,
428423 int last_shell = binding_energy_.shape ()[0 ] - 1 ;
429424 double E_b = binding_energy_ (last_shell);
430425 double E = alpha * MASS_ELECTRON_EV;
431- double mu_max = 1 - E_b / (alpha * (E - E_b));
426+ if (E < E_b)
427+ fatal_error (" Cannot eject any electron" );
432428
433429 while (true ) {
434430 // Sample Klein-Nishina distribution for trial energy and angle
435431 std::tie (*alpha_out, *mu) = klein_nishina (alpha, seed);
436432
437- // If in every angle we cannot eject an electron
438- // Exit with no shell
439- if (mu_max < -1 ) {
440- *i_shell = -1 ;
441- return ;
442- }
443-
444- if (doppler) {
445- // Reject angles that cannot eject the most loosely bound electron
446- if (*mu > mu_max)
447- continue ;
448- }
449-
450433 // Note that the parameter used here does not correspond exactly to the
451434 // momentum transfer q in ENDF-102 Eq. (27.2). Rather, this is the
452435 // parameter as defined by Hubbell, where the actual data comes from
@@ -478,42 +461,37 @@ void PhotonInteraction::compton_doppler(
478461 double alpha, double mu, double * E_out, int * i_shell, uint64_t * seed) const
479462{
480463 auto n = data::compton_profile_pz.size ();
481- double E = alpha * MASS_ELECTRON_EV;
482- int j_shell = 0 ;
483- for (double E_b : binding_energy_) {
484- if ((E_b - (E - E_b) * alpha * (1.0 - mu)) < 0.0 )
485- break ;
486- ++j_shell;
487- }
488-
489- double offset = 0.0 ;
490- if (j_shell > 0 )
491- offset = electron_cdf_ (j_shell - 1 );
492464
493465 int shell; // index for shell
494466 while (true ) {
495467 // Sample electron shell
496- double rn = offset + prn (seed) * ( 1.0 - offset );
497- double c;
498- for (shell = j_shell ; shell < electron_cdf_ .size (); ++shell) {
499- c = electron_cdf_ (shell);
468+ double rn = prn (seed);
469+ double c = 0.0 ;
470+ for (shell = 0 ; shell < electron_pdf_ .size (); ++shell) {
471+ c += electron_pdf_ (shell);
500472 if (rn < c)
501473 break ;
502474 }
475+ double E = alpha * MASS_ELECTRON_EV;
503476
504477 // Determine binding energy of shell
505478 double E_b = binding_energy_ (shell);
506479
507- // Determine p_z,max
480+ // Resample if photon energy insufficient
481+ if (E < E_b)
482+ continue ;
483+
508484 double pz_max = -FINE_STRUCTURE * (E_b - (E - E_b) * alpha * (1.0 - mu)) /
509485 std::sqrt (2.0 * E * (E - E_b) * (1.0 - mu) + E_b * E_b);
486+
510487 // Determine profile cdf value corresponding to p_z,max
511488 double c_max;
512- if (pz_max > data::compton_profile_pz (n - 1 )) {
489+ if (std::abs (pz_max) > data::compton_profile_pz (n - 1 )) {
490+ // TODO: handle linear extrapolation in lin-log scales
513491 c_max = profile_cdf_ (shell, n - 1 );
514492 } else {
515493 int i = lower_bound_index (data::compton_profile_pz.cbegin (),
516- data::compton_profile_pz.cend (), pz_max);
494+ data::compton_profile_pz.cend (), std::abs ( pz_max) );
517495 double pz_l = data::compton_profile_pz (i);
518496 double pz_r = data::compton_profile_pz (i + 1 );
519497 double p_l = profile_pdf_ (shell, i);
@@ -522,10 +500,11 @@ void PhotonInteraction::compton_doppler(
522500 if (pz_l == pz_r) {
523501 c_max = c_l;
524502 } else if (p_l == p_r) {
525- c_max = c_l + (pz_max - pz_l) * p_l;
503+ c_max = c_l + (std::abs ( pz_max) - pz_l) * p_l;
526504 } else {
527505 double m = (p_l - p_r) / (pz_l - pz_r);
528- c_max = c_l + (std::pow ((m * (pz_max - pz_l) + p_l), 2 ) - p_l * p_l) /
506+ c_max = c_l + (std::pow ((m * (std::abs (pz_max) - pz_l) + p_l), 2 ) -
507+ p_l * p_l) /
529508 (2.0 * m);
530509 }
531510 }
@@ -561,22 +540,28 @@ void PhotonInteraction::compton_doppler(
561540
562541 double quad = b * b - 4.0 * a * c;
563542 if (quad < 0 )
564- continue ;
543+ fatal_error ( " Cannot doppler broaden. " ) ;
565544 quad = std::sqrt (quad);
566545 double E_out1 = -(b + quad) / (2.0 * a);
567546 double E_out2 = -(b - quad) / (2.0 * a);
568547
569- // If no positive solution -- resample
570- if (std::max (E_out1, E_out2) < 0 )
571- continue ;
572-
573548 // Determine solution to quadratic equation that is positive
574- if ((E_out1 > 0.0 ) && (E_out2 > 0.0 )) {
575- *E_out = prn (seed) < 0.5 ? E_out1 : E_out2;
549+ if (E_out1 > 0.0 ) {
550+ if (E_out2 > 0.0 ) {
551+ // If both are positive, pick one at random
552+ *E_out = prn (seed) < 0.5 ? E_out1 : E_out2;
553+ } else {
554+ *E_out = E_out1;
555+ }
576556 } else {
577- *E_out = std::max (E_out1, E_out2);
557+ if (E_out2 > 0.0 ) {
558+ *E_out = E_out2;
559+ } else {
560+ // No positive solution -- resample
561+ continue ;
562+ }
578563 }
579- if (*E_out < E - E_b )
564+ if (prn (seed) * E <= *E_out )
580565 break ;
581566 }
582567
0 commit comments