Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Speed up the legendre root finding (used in gauss-legendre grid) #629

Merged
merged 4 commits into from
Feb 18, 2025

Conversation

HengruiZhu99
Copy link
Collaborator

updating the bisection solver by a newton raphson finder as @dradice suggested. Now speed up the code by quite a bit. I also included a unit test for doing cross integration of spherical harmonics on Gauss-Legendre grid. The integral is calculated robustly up to l_max=20, loss of precision seen at l_max>=25, generating an error on the order of 1e-8 for higher l's. This is quite enough for CCE but should be kept in mind for future usage. Perhaps using precomputed values for the legendre roots and weights, or using the gsl implementation would be more robust.

Copy link
Collaborator

@dradice dradice left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have suggested a few more tweaks to improve accuracy and speed.


// Parameters for Newton iteration
double tol = 1e-14;
int max_iter = 100000;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think 100,000 iterations is way too many. You should be gaining 1 bit of precision at least per iteration and there are only 52 bits in a double precision number.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done! I left it the same as the N for bisection and forgot to update. The typical number of iteration to reach machine precision is 3, but I have set it to 20 for safety.

// For a large n, you might not need extremely large N
// if the function is well-behaved.
// But here we keep your original 60000 intervals.
roots_weights[1][i] = Ci(i, n, xi, -1.0, 1.0, 60000);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use analytic expression for the roots weights, e.g., Canuto, Hussaini, Quarteroni, Zang, Eq. (2.3.10)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Thanks for the reference!

std::vector<double> xi(n);

// Parameters for Newton iteration
double tol = 1e-14;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would iterate until floating point precision here. In my experience when $N \gtrsim 20$ the precision of the points become crucial for accuracy.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now set to std::numeric_limits::epsilon()

@HengruiZhu99
Copy link
Collaborator Author

@jmstone Ready to be merged!

@jmstone jmstone merged commit 7841b3c into main Feb 18, 2025
4 checks passed
@jmstone jmstone deleted the test_gauss_legendre branch February 18, 2025 16:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants