| 
 | 1 | +#include <cmath>  | 
 | 2 | +#include <common/common.h>  | 
 | 3 | + | 
 | 4 | +#ifdef __CUDACC__  | 
 | 5 | +#include <cufinufft/types.h>  | 
 | 6 | +#endif  | 
 | 7 | + | 
 | 8 | +namespace finufft {  | 
 | 9 | +namespace common {  | 
 | 10 | + | 
 | 11 | +void gaussquad(int n, double *xgl, double *wgl) {  | 
 | 12 | +  // n-node Gauss-Legendre quadrature, adapted from a code by Jason Kaye (2022-2023),  | 
 | 13 | +  // from the utils file of https://github.com/flatironinstitute/cppdlr version 1.2,  | 
 | 14 | +  // which is Apache-2 licensed. It uses Newton iteration from Chebyshev points.  | 
 | 15 | +  // Double-precision only.  | 
 | 16 | +  // Adapted by Barnett 6/8/25 to write nodes (xgl) and weights (wgl) into arrays  | 
 | 17 | +  // that the user must pre-allocate to length at least n.  | 
 | 18 | + | 
 | 19 | +  double x = 0, dx = 0;  | 
 | 20 | +  int convcount = 0;  | 
 | 21 | + | 
 | 22 | +  // Get Gauss-Legendre nodes  | 
 | 23 | +  xgl[n / 2] = 0;                   // If odd number of nodes, middle node is 0  | 
 | 24 | +  for (int i = 0; i < n / 2; i++) { // Loop through nodes  | 
 | 25 | +    convcount = 0;  | 
 | 26 | +    x         = std::cos((2 * i + 1) * PI / (2 * n)); // Initial guess: Chebyshev node  | 
 | 27 | +    while (true) {                               // Newton iteration  | 
 | 28 | +      auto [p, dp] = leg_eval(n, x);  | 
 | 29 | +      dx           = -p / dp;  | 
 | 30 | +      x += dx; // Newton step  | 
 | 31 | +      if (std::abs(dx) < 1e-14) {  | 
 | 32 | +        convcount++;  | 
 | 33 | +      }  | 
 | 34 | +      if (convcount == 3) {  | 
 | 35 | +        break;  | 
 | 36 | +      } // If convergence tol hit 3 times, stop  | 
 | 37 | +    }  | 
 | 38 | +    xgl[i]         = -x;  | 
 | 39 | +    xgl[n - i - 1] = x; // Symmetric nodes  | 
 | 40 | +  }  | 
 | 41 | + | 
 | 42 | +  // Get Gauss-Legendre weights from formula  | 
 | 43 | +  // w_i = -2 / ((n+1)*P_n'(x_i)*P_{n+1}(x_i)) (Atkinson '89, pg. 276)  | 
 | 44 | +  for (int i = 0; i < n / 2 + 1; i++) {  | 
 | 45 | +    auto [junk1, dp] = leg_eval(n, xgl[i]);  | 
 | 46 | +    auto [p, junk2]  = leg_eval(n + 1, xgl[i]); // This is a bit inefficient, but who  | 
 | 47 | +                                                // cares...  | 
 | 48 | +    wgl[i]         = -2 / ((n + 1) * dp * p);  | 
 | 49 | +    wgl[n - i - 1] = wgl[i];  | 
 | 50 | +  }  | 
 | 51 | +}  | 
 | 52 | + | 
 | 53 | +std::tuple<double, double> leg_eval(int n, double x) {  | 
 | 54 | +  // return Legendre polynomial P_n(x) and its derivative P'_n(x).  | 
 | 55 | +  // Uses Legendre three-term recurrence.  | 
 | 56 | +  // Used by gaussquad above, with which it shares the same authorship and source.  | 
 | 57 | + | 
 | 58 | +  if (n == 0) {  | 
 | 59 | +    return {1.0, 0.0};  | 
 | 60 | +  }  | 
 | 61 | +  if (n == 1) {  | 
 | 62 | +    return {x, 1.0};  | 
 | 63 | +  }  | 
 | 64 | +  // Three-term recurrence and formula for derivative  | 
 | 65 | +  double p0 = 0.0, p1 = 1.0, p2 = x;  | 
 | 66 | +  for (int i = 1; i < n; i++) {  | 
 | 67 | +    p0 = p1;  | 
 | 68 | +    p1 = p2;  | 
 | 69 | +    p2 = ((2 * i + 1) * x * p1 - i * p0) / (i + 1);  | 
 | 70 | +  }  | 
 | 71 | +  return {p2, n * (x * p2 - p1) / (x * x - 1)};  | 
 | 72 | +}  | 
 | 73 | + | 
 | 74 | +} // namespace common  | 
 | 75 | +} // namespace finufft  | 
 | 76 | + | 
 | 77 | +namespace cufinufft {  | 
 | 78 | +namespace utils {  | 
 | 79 | + | 
 | 80 | +long next235beven(long n, long b)  | 
 | 81 | +// finds even integer not less than n, with prime factors no larger than 5  | 
 | 82 | +// (ie, "smooth") and is a multiple of b (b is a number that the only prime  | 
 | 83 | +// factors are 2,3,5). Adapted from fortran in hellskitchen. Barnett 2/9/17  | 
 | 84 | +// changed INT64 type 3/28/17. Runtime is around n*1e-11 sec for big n.  | 
 | 85 | +// added condition about b, Melody Shih 05/31/20  | 
 | 86 | +{  | 
 | 87 | +  if (n <= 2) return 2;  | 
 | 88 | +  if (n % 2 == 1) n += 1;                // even  | 
 | 89 | +  long nplus  = n - 2;                   // to cancel out the +=2 at start of loop  | 
 | 90 | +  long numdiv = 2;                       // a dummy that is >1  | 
 | 91 | +  while ((numdiv > 1) || (nplus % b != 0)) {  | 
 | 92 | +    nplus += 2;                          // stays even  | 
 | 93 | +    numdiv = nplus;  | 
 | 94 | +    while (numdiv % 2 == 0) numdiv /= 2; // remove all factors of 2,3,5...  | 
 | 95 | +    while (numdiv % 3 == 0) numdiv /= 3;  | 
 | 96 | +    while (numdiv % 5 == 0) numdiv /= 5;  | 
 | 97 | +  }  | 
 | 98 | +  return nplus;  | 
 | 99 | +}  | 
 | 100 | + | 
 | 101 | +} // namespace utils  | 
 | 102 | +} // namespace cufinufft  | 
0 commit comments