LCOV - code coverage report
Current view: top level - src/userobjects - ScatteringRecoilCrossSection.C (source / functions) Hit Total Coverage
Test: idaholab/magpie: 5710af Lines: 99 116 85.3 %
Date: 2025-07-21 23:34:39 Functions: 5 10 50.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /**********************************************************************/
       2             : /*                     DO NOT MODIFY THIS HEADER                      */
       3             : /* MAGPIE - Mesoscale Atomistic Glue Program for Integrated Execution */
       4             : /*                                                                    */
       5             : /*            Copyright 2017 Battelle Energy Alliance, LLC            */
       6             : /*                        ALL RIGHTS RESERVED                         */
       7             : /**********************************************************************/
       8             : #ifdef GSL_ENABLED
       9             : 
      10             : #include "ScatteringRecoilCrossSection.h"
      11             : #include "MagpieUtils.h"
      12             : #include "Function.h"
      13             : 
      14             : // gsl includes
      15             : #include "gsl/gsl_sf_legendre.h"
      16             : #include "gsl/gsl_integration.h"
      17             : 
      18             : InputParameters
      19          96 : ScatteringRecoilCrossSection::validParams()
      20             : {
      21          96 :   InputParameters params = GeneralUserObject::validParams();
      22          96 :   params.addClassDescription(
      23             :       "Base class for computing recoil scattering cross sections for a single isotope."
      24             :       "It outputs the coefficients for the Legendre expansion of the cross section up to the "
      25             :       "specified Legendre expansion order"
      26             :       "polynomials l, neutron energy groups g and recoil energy bins t. It also outputs the "
      27             :       "maximum and mininum"
      28             :       "cosines of the recoil atom in the laboratory frame.");
      29         192 :   params.addParam<unsigned int>("quadrature_order", 400, "Quadrature order for integration");
      30         192 :   params.addParam<Real>("atomic_mass", 1, "Atomic Mass of the isotope. Default to Hydrogen A = 1");
      31         192 :   params.addRequiredParam<std::vector<Real>>(
      32             :       "neutron_energy_limits",
      33             :       "Energy limits of the incident neutron in [eV] and descending order");
      34         192 :   params.addRequiredParam<std::vector<Real>>(
      35             :       "recoil_energy_limits", "Energy limits of the recoil atom in [eV] and descending order");
      36         192 :   params.addRequiredParam<FunctionName>("neutron_spectrum",
      37             :                                         "Function representing the reactor neutron spectrum");
      38         192 :   params.addRequiredParam<std::vector<FunctionName>>("scattering_xs",
      39             :                                                      "Functions representing the neutron cross "
      40             :                                                      "sections. NOTE: this is a vector to allow "
      41             :                                                      "separate inputs for inelastic modes.");
      42         192 :   params.addParam<unsigned int>(
      43         192 :       "legendre_order", 10, "Order of Legendre polynomials where n = 0, ..., 10. Default to P10");
      44         192 :   params.addParam<std::string>(
      45             :       "cross_section_output_filename",
      46             :       "Name of the output file with the cross section coefficients (.csv)");
      47         192 :   params.addParam<std::string>("mu_L_output_filename",
      48             :                                "Name of the output file with the mininum and maximum mu_L (.csv)");
      49          96 :   return params;
      50           0 : }
      51             : 
      52          48 : ScatteringRecoilCrossSection::ScatteringRecoilCrossSection(const InputParameters & parameters)
      53             :   : GeneralUserObject(parameters),
      54          48 :     _csv_tolerance(1.0e-10),
      55          48 :     _quad_order(getParam<unsigned int>("quadrature_order")),
      56          48 :     _neutron_spectrum(getFunction("neutron_spectrum")),
      57          96 :     _L(getParam<unsigned int>("legendre_order")),
      58          96 :     _atomic_mass(getParam<Real>("atomic_mass")),
      59          96 :     _neutron_energy_limits(getParam<std::vector<Real>>("neutron_energy_limits")),
      60         192 :     _recoil_energy_limits(getParam<std::vector<Real>>("recoil_energy_limits"))
      61             : {
      62         144 :   if (isParamValid("cross_section_output_filename") ^ isParamValid("mu_L_output_filename"))
      63           0 :     mooseError("cross_section_output_filename and mu_L_output_filename must either both be present "
      64             :                "or absent");
      65             : 
      66             :   // get scattering cross sections
      67         144 :   std::vector<FunctionName> xs_names = getParam<std::vector<FunctionName>>("scattering_xs");
      68          48 :   _scattering_cross_section.resize(xs_names.size());
      69          96 :   for (unsigned int j = 0; j < xs_names.size(); ++j)
      70          48 :     _scattering_cross_section[j] = &getFunctionByName(xs_names[j]);
      71             : 
      72             :   // set up integration rule
      73          48 :   auto * qp_table = gsl_integration_glfixed_table_alloc(_quad_order);
      74          48 :   _quad_points.resize(_quad_order);
      75          48 :   _quad_weights.resize(_quad_order);
      76       20848 :   for (std::size_t j = 0; j < _quad_order; ++j)
      77             :   {
      78             :     double point, weight;
      79       20800 :     gsl_integration_glfixed_point(-1.0, 1.0, j, &point, &weight, qp_table);
      80       20800 :     _quad_points[j] = point;
      81       20800 :     _quad_weights[j] = weight;
      82             :   }
      83          48 :   gsl_integration_glfixed_table_free(qp_table);
      84             : 
      85          48 :   _alpha = std::pow(((_atomic_mass - 1) / (_atomic_mass + 1)), 2);
      86          48 :   _gamma = 4 * _atomic_mass / std::pow((_atomic_mass + 1), 2);
      87          48 :   _G = _neutron_energy_limits.size() - 1;
      88          48 :   _T = _recoil_energy_limits.size() - 1;
      89          48 : }
      90             : 
      91             : void
      92          12 : ScatteringRecoilCrossSection::initialize()
      93             : {
      94             :   // Calculate neutron spectrum over group g
      95          12 :   _xi_g.resize(_G);
      96          24 :   for (unsigned int g = 0; g < _G; ++g)
      97             :   {
      98          12 :     Real E_u = _neutron_energy_limits[g];
      99          12 :     Real E_l = _neutron_energy_limits[g + 1];
     100             : 
     101        4812 :     for (unsigned int p = 0; p < _quad_points.size(); ++p)
     102             :     {
     103        4800 :       Real E = 0.5 * (E_u - E_l) * _quad_points[p] + 0.5 * (E_u + E_l);
     104        4800 :       Real w_E = 0.5 * _quad_weights[p] * (E_u - E_l);
     105        4800 :       _xi_g[g] += w_E * _neutron_spectrum.value(E, Point());
     106             :     }
     107             :   }
     108             : 
     109             :   // Size the cross section array
     110          12 :   _recoil_coefficient.resize(_L + 1);
     111          56 :   for (unsigned int l = 0; l < _L + 1; ++l)
     112             :   {
     113          44 :     _recoil_coefficient[l].resize(_T);
     114         228 :     for (unsigned int t = 0; t < _T; ++t)
     115         184 :       _recoil_coefficient[l][t].assign(_G, 0.0);
     116             :   }
     117             : 
     118             :   // Size the lab frame cosine array and initialize to -1, both lab cosines -1 means
     119             :   // this g->t combination is impossible
     120          12 :   _mu_L.resize(_T);
     121          68 :   for (unsigned int t = 0; t < _T; ++t)
     122             :   {
     123          56 :     _mu_L[t].resize(_G);
     124         112 :     for (unsigned int g = 0; g < _G; ++g)
     125          56 :       _mu_L[t][g].assign(2, -1.0);
     126             :   }
     127          12 : }
     128             : 
     129             : void
     130          12 : ScatteringRecoilCrossSection::finalize()
     131             : {
     132          48 :   if (!(isParamValid("cross_section_output_filename") && isParamValid("mu_L_output_filename")))
     133           0 :     return;
     134          24 :   _recoil_xs_file_name = getParam<std::string>("cross_section_output_filename");
     135          24 :   _mu_L_file_name = getParam<std::string>("mu_L_output_filename");
     136             : 
     137             :   /*
     138             :    * Write the elastic recoil cross section (g -> t) output file
     139             :    *
     140             :    *            t = 0              t = 1              t = ...
     141             :    *       l = 0, 1, 2, ...   l = 0, 1, 2, ...   l = 0, 1, 2, ...
     142             :    *  g 0
     143             :    *    1
     144             :    *    2
     145             :    *    .
     146             :    *    .
     147             :    *    .
     148             :    */
     149          12 :   std::ofstream output_file;
     150          12 :   output_file.open(_recoil_xs_file_name);
     151             : 
     152             :   // print header
     153          12 :   output_file << "Neutron group,";
     154          68 :   for (unsigned int t = 0; t < _T; ++t)
     155         240 :     for (unsigned int l = 0; l < _L + 1; ++l)
     156             :     {
     157         368 :       output_file << "Recoil group t = " << t << " Moment order l = " << l;
     158         184 :       if (!(t == _T - 1 && l == _L))
     159         172 :         output_file << ",";
     160             :     }
     161             :   output_file << std::endl;
     162             : 
     163             :   // print data
     164          24 :   for (unsigned int g = 0; g < _G; ++g)
     165             :   {
     166          12 :     output_file << g << ",";
     167          68 :     for (unsigned int t = 0; t < _T; ++t)
     168         240 :       for (unsigned int l = 0; l < _L + 1; ++l)
     169             :       {
     170         184 :         output_file << csvPrint(_recoil_coefficient[l][t][g]);
     171         184 :         if (!(t == _T - 1 && l == _L))
     172         172 :           output_file << ',';
     173             :       }
     174             :     output_file << std::endl;
     175             :   }
     176          12 :   output_file.close();
     177             : 
     178             :   /*
     179             :    * Writes output file with maximum and mininum cosines in the Lab frame (mu_L)
     180             :    * It follows same structure as ERXS outfile file, but saves the mu_L_min and
     181             :    * mu_L_max per g -> t combination.
     182             :    */
     183          12 :   std::ofstream output_file2;
     184          12 :   output_file2.open(_mu_L_file_name);
     185             :   // print header
     186          12 :   output_file2 << "Neutron group,";
     187          68 :   for (unsigned int t = 0; t < _T; ++t)
     188             :   {
     189          56 :     output_file2 << "Recoil group t = " << t << " mu_min,"
     190         112 :                  << "Recoil group t = " << t << " mu_max";
     191          56 :     if (t != _T - 1)
     192          44 :       output_file2 << ",";
     193             :   }
     194             :   output_file2 << std::endl;
     195             : 
     196             :   // print data
     197          24 :   for (unsigned int g = 0; g < _G; ++g)
     198             :   {
     199          12 :     output_file2 << g << ",";
     200          68 :     for (unsigned int t = 0; t < _T; ++t)
     201             :     {
     202         112 :       output_file2 << csvPrint(_mu_L[t][g][0]) << ',' << csvPrint(_mu_L[t][g][1]);
     203          56 :       if (t != _T - 1)
     204          44 :         output_file2 << ',';
     205             :     }
     206             :     output_file2 << std::endl;
     207             :   }
     208          12 :   output_file2.close();
     209          12 : }
     210             : 
     211             : // Find the neutron energy group given a neutron energy
     212             : unsigned int
     213           0 : ScatteringRecoilCrossSection::findNeutronEnergyGroup(Real energy)
     214             : {
     215           0 :   for (unsigned int g = 0; g < _G; ++g)
     216             :   {
     217           0 :     if (energy < _neutron_energy_limits[g] && energy > _neutron_energy_limits[g + 1])
     218           0 :       return g;
     219             :   }
     220           0 :   mooseError("Should never get here");
     221             : }
     222             : 
     223             : Real
     224         296 : ScatteringRecoilCrossSection::csvPrint(Real value) const
     225             : {
     226         296 :   if (std::abs(value) < _csv_tolerance)
     227          52 :     return 0;
     228             :   return value;
     229             : }
     230             : 
     231             : Real
     232           0 : ScatteringRecoilCrossSection::getSigmaRecoil(unsigned int g, unsigned int t, unsigned int l) const
     233             : {
     234             :   mooseAssert(g < _G, "g is larger than _G [indexed from g = 0, ..., G - 1]");
     235             :   mooseAssert(t < _T, "t is larger than _T [indexed from t = 0, ..., T - 1]");
     236           0 :   if (l <= _L)
     237           0 :     return _recoil_coefficient[l][t][g];
     238             :   return 0.0;
     239             : }
     240             : 
     241             : Real
     242           0 : ScatteringRecoilCrossSection::getMaxRecoilCosine(unsigned int g, unsigned t) const
     243             : {
     244             :   mooseAssert(g < _G, "g is larger than _G [indexed from g = 0, ..., G - 1]");
     245             :   mooseAssert(t < _T, "t is larger than _T [indexed from t = 0, ..., T - 1]");
     246           0 :   return _mu_L[t][g][1];
     247             : }
     248             : 
     249             : Real
     250           0 : ScatteringRecoilCrossSection::getMinRecoilCosine(unsigned int g, unsigned t) const
     251             : {
     252             :   mooseAssert(g < _G, "g is larger than _G [indexed from g = 0, ..., G - 1]");
     253             :   mooseAssert(t < _T, "t is larger than _T [indexed from t = 0, ..., T - 1]");
     254           0 :   return _mu_L[t][g][0];
     255             : }
     256             : 
     257             : bool
     258           0 : ScatteringRecoilCrossSection::isRecoilPossible(unsigned int g, unsigned int t) const
     259             : {
     260           0 :   return !(_mu_L[t][g][0] == -1 && _mu_L[t][g][1] == -1);
     261             : }
     262             : 
     263             : #endif

Generated by: LCOV version 1.14