Skip to content

Commit 8132dd9

Browse files
committed
added forgotten file
1 parent 98574aa commit 8132dd9

File tree

1 file changed

+102
-0
lines changed

1 file changed

+102
-0
lines changed

src/utils.cpp

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
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

Comments
 (0)