Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 08:54:06

0001 //------------------------------- -*- C++ -*- -------------------------------//
0002 // Copyright Celeritas contributors: see top-level COPYRIGHT file for details
0003 // SPDX-License-Identifier: (Apache-2.0 OR MIT)
0004 //---------------------------------------------------------------------------//
0005 //! \file corecel/grid/SplineDerivCalculator.hh
0006 //---------------------------------------------------------------------------//
0007 #pragma once
0008 
0009 #include <memory>
0010 #include <vector>
0011 
0012 #include "corecel/Assert.hh"
0013 #include "corecel/Macros.hh"
0014 #include "corecel/Types.hh"
0015 #include "corecel/cont/Span.hh"
0016 
0017 #include "GridTypes.hh"
0018 #include "UniformGrid.hh"
0019 
0020 #include "detail/GridAccessor.hh"
0021 
0022 namespace celeritas
0023 {
0024 //---------------------------------------------------------------------------//
0025 /*!
0026  * Calculate the second derivatives of a cubic spline.
0027  *
0028  * See section 3.3: Cubic Spline Interpolation in \cite{press-nr-1992} for a
0029  * review of interpolating cubic splines and an algorithm for calculating the
0030  * second derivatives.
0031  *
0032  * Determining the polynomial coefficients \$ a_0, a_1, a_2 \f$ and \$f a_3 \f$
0033  * of a cubic spline \f$ S(x) \f$ (see: \sa SplineInterpolator) requires
0034  * solving a tridiagonal, linear system of equations for the second
0035  * derivatives. For \f$ n \f$ points \f$ (x_i, y_i) \f$ and \f$ n \f$ unknowns
0036  * \f$ S''_i \f$ there are \f$ n - 2 \f$ equations of the form
0037  * \f[
0038    h_{i - 1} S''_{i - 1} + 2 (h_{i - 1} + h_i) S''i + h_i S''_{i + 1} = 6 r_i,
0039  * \f]
0040  * where \f$ r_i = frac{\Delta y_i}{h_i} - frac{\Delta y_{i - 1}}{h_{i - 1}}
0041  * \f$ and \f$ h_i = \Delta x_i = x_{i + 1} - x_i \f$.
0042  *
0043  * Specifying the boundary conditions gives the remaining two equations.
0044  * Natural boundary conditions set \f$ S''_0 = S''_{n - 1} = 0 \f$, which leads
0045  * to the following initial and final equations:
0046  * \f{align}{
0047    2 (h_0 + h_1) S''_1 + h_1 S''_2 &= 6 r_1 //
0048    h_{n - 3} S''_{n - 3} + 2 (h_{n - 3} + h_{n - 2}) S''_{n - 2}
0049    &= 6 r_{n - 2}.
0050  * \f}
0051  *
0052  * The points \f$ x_0, x_1, \dots , x_{n - 1} \f$ where the spline changes from
0053  * one cubic to the next are called knots. "Not-a-knot" boundary conditions
0054  * require the third derivative \f$ S'''_i \f$ to be continous across the first
0055  * and final interior knots, \f$ x_1 \f$ and \f$ x_{n - 2} \f$ (the name refers
0056  * to the polynomials on the interval \f$ (x_0, x_1) \f$  and \f$ (x_1, x_2)
0057  * \f$ being the same cubic, so \f$ x_1 \f$ is "not a knot"). This constraint
0058  * gives the final two equations:
0059  * \f{align}{
0060    \frac{(h_0 + 2 h_1)(h_0 + h_1)}{h_1} S''_1 + \frac{h_1^2 - h_0^2}{h_1}
0061    S''_2 &= 6 r_1 //
0062    \frac{h_{n - 3}^2 - h_{n - 2}^2}{h_{n - 3}} S''_{n - 3} + \frac{(h_{n - 3}
0063    + h_{n - 2})(2 h_{n - 3} + h_{n - 2})}{h_{n - 3}} S''_{n - 2} &= 6 r_{n - 2}
0064  * \f}
0065  * Once the system of equations has been solved for the second derivatives, the
0066  * derivatives \f$ S''_0 \f$ and \f$ S''_{n - 1} \f$ can be recovered:
0067  * \f{align}{
0068    S''_0 &= \frac{(h_0 + h_1) S''_1 - h_0 S''_2}{h_1} \\
0069    S''_{n - 1} &= \frac{(h_{n - 3} + h_{n - 2}) S''_{n - 2} - h_{n - 2}
0070    S''_{n - 3}}{h_{n - 3}}
0071  * \f}
0072  */
0073 class SplineDerivCalculator
0074 {
0075   public:
0076     //!@{
0077     //! \name Type aliases
0078     using SpanConstReal = detail::GridAccessor::SpanConstReal;
0079     using Values = detail::GridAccessor::Values;
0080     using VecReal = std::vector<real_type>;
0081     using BoundaryCondition = SplineBoundaryCondition;
0082     //!@}
0083 
0084   public:
0085     // Construct with boundary conditions
0086     explicit SplineDerivCalculator(BoundaryCondition);
0087 
0088     // Calculate the second derivatives
0089     VecReal operator()(SpanConstReal, SpanConstReal) const;
0090     VecReal operator()(UniformGridRecord const&, Values const&) const;
0091     VecReal operator()(NonuniformGridRecord const&, Values const&) const;
0092 
0093     // Calculate the second derivatives from an inverted uniform grid
0094     VecReal calc_from_inverse(UniformGridRecord const&, Values const&) const;
0095 
0096     //! Minimum grid size for cubic spline interpolation
0097     static CELER_CONSTEXPR_FUNCTION int min_grid_size() { return 5; }
0098 
0099   private:
0100     //// TYPES ////
0101 
0102     using Real3 = Array<real_type, 3>;
0103 
0104     //// DATA ////
0105 
0106     BoundaryCondition bc_;
0107 
0108     //// HELPER FUNCTIONS ////
0109 
0110     template<class GridAccessor>
0111     VecReal operator()(GridAccessor&&) const;
0112 
0113     template<class GridAccessor>
0114     void calc_initial_coeffs(GridAccessor const&, Real3&, real_type&) const;
0115     template<class GridAccessor>
0116     void calc_final_coeffs(GridAccessor const&, Real3&, real_type&) const;
0117     template<class GridAccessor>
0118     void calc_boundaries(GridAccessor const&, VecReal&) const;
0119     template<class GridAccessor>
0120     VecReal calc_geant_derivatives(GridAccessor const&) const;
0121 };
0122 
0123 //---------------------------------------------------------------------------//
0124 }  // namespace celeritas