Commit 726d9fbba902bc10d4cbe086dc7c91b9c6450329
1 parent
399c038c
Implement vectorised polynomial interpolation in GIntegrals class (#3203)
Showing
2 changed files
with
74 additions
and
66 deletions
include/GIntegrals.hpp
| ... | ... | @@ -88,15 +88,14 @@ public: |
| 88 | 88 | |
| 89 | 89 | protected: |
| 90 | 90 | // Protected methods |
| 91 | - void init_members(void); | |
| 92 | - void copy_members(const GIntegrals& integral); | |
| 93 | - void free_members(void); | |
| 94 | - double polint(const double* xa, | |
| 95 | - const GVector* ya, | |
| 96 | - const int& n, | |
| 97 | - const int& index, | |
| 98 | - const double& x, | |
| 99 | - double* dy); | |
| 91 | + void init_members(void); | |
| 92 | + void copy_members(const GIntegrals& integral); | |
| 93 | + void free_members(void); | |
| 94 | + GVector polint(const double* xa, | |
| 95 | + const GVector* ya, | |
| 96 | + const int& order, | |
| 97 | + const double& x, | |
| 98 | + GVector* dy); | |
| 100 | 99 | |
| 101 | 100 | // Protected data area |
| 102 | 101 | GFunctions* m_kernels; //!< Pointer to function kernels | ... | ... |
src/numerics/GIntegrals.cpp
| ... | ... | @@ -333,12 +333,7 @@ GVector GIntegrals::romberg(const double& a, const double& b, const int& order) |
| 333 | 333 | if (m_iter >= order) { |
| 334 | 334 | |
| 335 | 335 | // Compute result using polynom interpolation |
| 336 | - for (int i = 0; i < result.size(); ++i) { | |
| 337 | - double dy = 0; | |
| 338 | - result[i] = polint(&h[m_iter-order], &s[m_iter-order], | |
| 339 | - order, i, 0.0, &dy); | |
| 340 | - dss[i] = dy; | |
| 341 | - } | |
| 336 | + result = polint(&h[m_iter-order], &s[m_iter-order], order, 0.0, &dss); | |
| 342 | 337 | |
| 343 | 338 | // If a fixed number of iterations has been requested and if |
| 344 | 339 | // the final iteration was reached then set the converged |
| ... | ... | @@ -711,80 +706,94 @@ void GIntegrals::free_members(void) |
| 711 | 706 | * |
| 712 | 707 | * @param[in] xa Pointer to array of X values. |
| 713 | 708 | * @param[in] ya Pointer to GVector of Y values. |
| 714 | - * @param[in] n Number of elements in arrays. | |
| 715 | - * @param[in] index GVector index for with interpolations should be performed. | |
| 709 | + * @param[in] order Number of elements in arrays. | |
| 716 | 710 | * @param[in] x X value for which interpolations should be performed. |
| 717 | - * @param[out] dy Pointer to array of error estimates for interpolated values. | |
| 718 | - * @return Interpolated value. | |
| 711 | + * @param[out] dy Pointer to vector of error estimates for interpolated values. | |
| 712 | + * @return Vector of interpolated values. | |
| 719 | 713 | * |
| 720 | 714 | * Given arrays @p xa[1,..,n] and @p ya[1,..,n], and given a value @p x, this |
| 721 | 715 | * method returns a value y, and an error estimate @p dy. If P(x) is the |
| 722 | 716 | * polynomial of degree n-1, then the returned value y=P(x). |
| 723 | 717 | ***************************************************************************/ |
| 724 | -double GIntegrals::polint(const double* xa, | |
| 725 | - const GVector* ya, | |
| 726 | - const int& n, | |
| 727 | - const int& index, | |
| 728 | - const double& x, | |
| 729 | - double* dy) | |
| 718 | +GVector GIntegrals::polint(const double* xa, | |
| 719 | + const GVector* ya, | |
| 720 | + const int& order, | |
| 721 | + const double& x, | |
| 722 | + GVector* dy) | |
| 730 | 723 | { |
| 724 | + // Get vector dimension | |
| 725 | + int nsize = ya->size(); | |
| 726 | + | |
| 731 | 727 | // Initialise result |
| 732 | - double y = 0.0; | |
| 728 | + GVector y(nsize); | |
| 733 | 729 | |
| 734 | 730 | // Allocate temporary memory |
| 735 | - double* c = new double[n]; | |
| 736 | - double* d = new double[n]; | |
| 737 | - | |
| 738 | - // Compute initial distance to first node | |
| 739 | - double dif = std::abs(x-xa[1]); | |
| 731 | + double* c = new double[order]; | |
| 732 | + double* d = new double[order]; | |
| 740 | 733 | |
| 741 | - // Find index ns of the closest table entry | |
| 742 | - int ns = 0; | |
| 743 | - for (int i = 0; i < n; ++i) { | |
| 734 | + // Find index nclosest of the closest table entry | |
| 735 | + int nclosest = 0; | |
| 736 | + double dif = std::abs(x-xa[1]); | |
| 737 | + for (int i = 1; i < order; ++i) { | |
| 744 | 738 | double dift = std::abs(x-xa[i+1]); |
| 745 | 739 | if (dift < dif) { |
| 746 | - ns = i; | |
| 747 | - dif = dift; | |
| 740 | + nclosest = i; | |
| 741 | + dif = dift; | |
| 748 | 742 | } |
| 749 | - double value = ya[i+1][index]; | |
| 750 | - c[i] = value; | |
| 751 | - d[i] = value; | |
| 752 | 743 | } |
| 753 | 744 | |
| 754 | - // Get initial approximation to y | |
| 755 | - y = ya[ns+1][index]; | |
| 756 | - ns--; | |
| 745 | + // Loop over vector dimension | |
| 746 | + for (int index = 0; index < nsize; ++index) { | |
| 757 | 747 | |
| 758 | - // Loop over each column of the tableau | |
| 759 | - for (int m = 1; m < n; ++m) { | |
| 748 | + // Set closest table entry | |
| 749 | + int ns = nclosest; | |
| 760 | 750 | |
| 761 | - // Update current c's and d's | |
| 762 | - for (int i = 0; i < n-m; ++i) { | |
| 763 | - double ho = xa[i+1] - x; | |
| 764 | - double hp = xa[i+m+1] - x; | |
| 765 | - double w = c[i+1] - d[i]; | |
| 766 | - double den = ho - hp; | |
| 767 | - if (den == 0.0) { | |
| 768 | - m_isvalid = false; | |
| 769 | - m_message = "Invalid step size "+gammalib::str(den)+ | |
| 770 | - " encountered. Two values in xa array are" | |
| 771 | - " identical."; | |
| 772 | - if (!m_silent) { | |
| 773 | - gammalib::warning(G_POLINT, m_message); | |
| 751 | + // Initialise table values | |
| 752 | + for (int i = 0; i < order; ++i) { | |
| 753 | + double value = ya[i+1][index]; | |
| 754 | + c[i] = value; | |
| 755 | + d[i] = value; | |
| 756 | + } | |
| 757 | + | |
| 758 | + // Get initial approximation to y | |
| 759 | + y[index] = ya[ns+1][index]; | |
| 760 | + ns--; | |
| 761 | + | |
| 762 | + // Loop over each column of the tableau | |
| 763 | + for (int m = 1; m < order; ++m) { | |
| 764 | + | |
| 765 | + // Update current c's and d's | |
| 766 | + for (int i = 0; i < order-m; ++i) { | |
| 767 | + double ho = xa[i+1] - x; | |
| 768 | + double hp = xa[i+m+1] - x; | |
| 769 | + double w = c[i+1] - d[i]; | |
| 770 | + double den = ho - hp; | |
| 771 | + if (den == 0.0) { | |
| 772 | + m_isvalid = false; | |
| 773 | + m_message = "Invalid step size "+gammalib::str(den)+ | |
| 774 | + " encountered. Two values in xa array are" | |
| 775 | + " identical."; | |
| 776 | + if (!m_silent) { | |
| 777 | + gammalib::warning(G_POLINT, m_message); | |
| 778 | + } | |
| 774 | 779 | } |
| 780 | + den = w/den; | |
| 781 | + d[i] = hp*den; | |
| 782 | + c[i] = ho*den; | |
| 775 | 783 | } |
| 776 | - den = w/den; | |
| 777 | - d[i] = hp*den; | |
| 778 | - c[i] = ho*den; | |
| 779 | - } | |
| 780 | 784 | |
| 781 | - // Compute y correction | |
| 782 | - *dy = (2*(ns+1) < (n-m)) ? c[ns+1] : d[ns--]; | |
| 785 | + // Compute y correction | |
| 786 | + double delta_y = (2*(ns+1) < (order-m)) ? c[ns+1] : d[ns--]; | |
| 787 | + | |
| 788 | + // Update y | |
| 789 | + y[index] += delta_y; | |
| 790 | + | |
| 791 | + // Store result | |
| 792 | + (*dy)[index] = delta_y; | |
| 783 | 793 | |
| 784 | - // Update y | |
| 785 | - y += *dy; | |
| 794 | + } // endfor: looped over columns of tableau | |
| 786 | 795 | |
| 787 | - } // endfor: looped over columns of tableau | |
| 796 | + } // endfor: looped over vector dimension | |
| 788 | 797 | |
| 789 | 798 | // Free temporary memory |
| 790 | 799 | delete [] c; | ... | ... |