Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-02-22 10:31:23

0001 //----------------------------------*-C++-*----------------------------------//
0002 // Copyright 2020-2024 UT-Battelle, LLC, and other Celeritas developers.
0003 // See the top-level COPYRIGHT file for details.
0004 // SPDX-License-Identifier: (Apache-2.0 OR MIT)
0005 //---------------------------------------------------------------------------//
0006 //! \file celeritas/grid/XsCalculator.hh
0007 //---------------------------------------------------------------------------//
0008 #pragma once
0009 
0010 #include <cmath>
0011 
0012 #include "corecel/grid/Interpolator.hh"
0013 #include "corecel/grid/UniformGrid.hh"
0014 #include "corecel/math/Quantity.hh"
0015 
0016 #include "XsGridData.hh"
0017 
0018 namespace celeritas
0019 {
0020 //---------------------------------------------------------------------------//
0021 /*!
0022  * Find and interpolate cross sections on a uniform log grid.
0023  *
0024  * \todo Currently this is hard-coded to use "cross section grid data"
0025  * which have energy coordinates uniform in log space. This should
0026  * be expanded to handle multiple parameterizations of the energy grid (e.g.,
0027  * arbitrary spacing needed for the Livermore sampling) and of the value
0028  * interpolation (e.g. log interpolation). It might also make sense to get rid
0029  * of the "prime energy" and just use log-log interpolation instead, or do a
0030  * piecewise change in the interpolation instead of storing the cross section
0031  * scaled by the energy.
0032  *
0033  * \code
0034     XsCalculator calc_xs(xs_grid, xs_params.reals);
0035     real_type xs = calc_xs(particle);
0036    \endcode
0037  */
0038 class XsCalculator
0039 {
0040   public:
0041     //!@{
0042     //! \name Type aliases
0043     using Energy = Quantity<XsGridData::EnergyUnits>;
0044     using Values
0045         = Collection<real_type, Ownership::const_reference, MemSpace::native>;
0046     //!@}
0047 
0048   public:
0049     // Construct from state-independent data
0050     inline CELER_FUNCTION
0051     XsCalculator(XsGridData const& grid, Values const& values);
0052 
0053     // Find and interpolate from the energy
0054     inline CELER_FUNCTION real_type operator()(Energy energy) const;
0055 
0056     // Get the cross section at the given index
0057     inline CELER_FUNCTION real_type operator[](size_type index) const;
0058 
0059     // Get the minimum energy
0060     CELER_FUNCTION Energy energy_min() const
0061     {
0062         return Energy(std::exp(loge_grid_.front()));
0063     }
0064 
0065     // Get the maximum energy
0066     CELER_FUNCTION Energy energy_max() const
0067     {
0068         return Energy(std::exp(loge_grid_.back()));
0069     }
0070 
0071   private:
0072     XsGridData const& data_;
0073     Values const& reals_;
0074     UniformGrid loge_grid_;
0075 
0076     CELER_FORCEINLINE_FUNCTION real_type get(size_type index) const;
0077 };
0078 
0079 //---------------------------------------------------------------------------//
0080 // INLINE DEFINITIONS
0081 //---------------------------------------------------------------------------//
0082 /*!
0083  * Construct from cross section data.
0084  */
0085 CELER_FUNCTION
0086 XsCalculator::XsCalculator(XsGridData const& grid, Values const& values)
0087     : data_(grid), reals_(values), loge_grid_(data_.log_energy)
0088 {
0089     CELER_EXPECT(data_);
0090     CELER_ASSERT(grid.value.size() == data_.log_energy.size);
0091 }
0092 
0093 //---------------------------------------------------------------------------//
0094 /*!
0095  * Calculate the cross section.
0096  *
0097  * If needed, we can add a "log(energy/MeV)" accessor if we constantly reuse
0098  * that value and don't want to repeat the `std::log` operation.
0099  */
0100 CELER_FUNCTION real_type XsCalculator::operator()(Energy energy) const
0101 {
0102     real_type const loge = std::log(energy.value());
0103 
0104     // Snap out-of-bounds values to closest grid points
0105     size_type lower_idx;
0106     real_type result;
0107     if (loge <= loge_grid_.front())
0108     {
0109         lower_idx = 0;
0110         result = this->get(lower_idx);
0111     }
0112     else if (loge >= loge_grid_.back())
0113     {
0114         lower_idx = loge_grid_.size() - 1;
0115         result = this->get(lower_idx);
0116     }
0117     else
0118     {
0119         // Locate the energy bin
0120         lower_idx = loge_grid_.find(loge);
0121         CELER_ASSERT(lower_idx + 1 < loge_grid_.size());
0122 
0123         real_type const upper_energy = std::exp(loge_grid_[lower_idx + 1]);
0124         real_type upper_xs = this->get(lower_idx + 1);
0125         if (lower_idx + 1 == data_.prime_index)
0126         {
0127             // Cross section data for the upper point has *already* been scaled
0128             // by E -- undo the scaling.
0129             upper_xs /= upper_energy;
0130         }
0131 
0132         // Interpolate *linearly* on energy using the lower_idx data.
0133         LinearInterpolator<real_type> interpolate_xs(
0134             {std::exp(loge_grid_[lower_idx]), this->get(lower_idx)},
0135             {upper_energy, upper_xs});
0136         result = interpolate_xs(energy.value());
0137     }
0138 
0139     if (lower_idx >= data_.prime_index)
0140     {
0141         result /= energy.value();
0142     }
0143     return result;
0144 }
0145 
0146 //---------------------------------------------------------------------------//
0147 /*!
0148  * Get the cross section at the given index.
0149  */
0150 CELER_FUNCTION real_type XsCalculator::operator[](size_type index) const
0151 {
0152     real_type energy = std::exp(loge_grid_[index]);
0153     real_type result = this->get(index);
0154 
0155     if (index >= data_.prime_index)
0156     {
0157         result /= energy;
0158     }
0159     return result;
0160 }
0161 
0162 //---------------------------------------------------------------------------//
0163 /*!
0164  * Get the raw cross section data at a particular index.
0165  */
0166 CELER_FUNCTION real_type XsCalculator::get(size_type index) const
0167 {
0168     CELER_EXPECT(index < data_.value.size());
0169     return reals_[data_.value[index]];
0170 }
0171 
0172 //---------------------------------------------------------------------------//
0173 }  // namespace celeritas