-
Notifications
You must be signed in to change notification settings - Fork 13
Lindh-Malmqvist-Gagliardi Radial Grid #84
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
Draft
wavefunction91
wants to merge
22
commits into
master
Choose a base branch
from
feature/lmg
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from 8 commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
9256a78
Add Lambert-W0 implementation for inverting exponential products
wavefunction91 7fe816f
Added and tested Lambert Wm1 function
wavefunction91 7853fed
Added LMG utility functions to compute upper/lower radial bounds
wavefunction91 54f13f4
Added LMG utility to compute step size for radial grid of a given pre…
wavefunction91 26f9c63
Remove boost header
wavefunction91 7b71e32
Added parameter fall through for lmg::r_lower per source provided by …
wavefunction91 7e71f94
Start LMG RadialTraits + misc dox++
wavefunction91 6c41dde
Added initial implementation of LMG + UTs
wavefunction91 cb6a4f9
Added implementations of integer and half-integer math functions
wavefunction91 bbb2483
Replace tgamma with half_integer_tgamma where appropriate
wavefunction91 6495dc5
Added integer POW routines
wavefunction91 2ef9ca3
function wrappers
wavefunction91 bdc342e
Add util_test to Ctest
wavefunction91 80e592c
Add INTEGRATORXX_HEADER_ONLY + requisite source refactor to enable he…
wavefunction91 482d871
Update README with header-only instructions
wavefunction91 e92cb07
Add header-only to CI
wavefunction91 e1a440b
Merge branch 'feature/lmg' of github.com:wavefunction91/IntegratorXX …
wavefunction91 861cc16
Merge branch 'feature/lmg' of github.com:wavefunction91/IntegratorXX …
wavefunction91 bd95ee0
Testing LMG grids
wavefunction91 6e23fe1
Merge branch 'feature/header_only' into merge_header_only_into_lmg
wavefunction91 dba0abc
Make LMG work with new RadialTraits schema
wavefunction91 15ed819
Add LMG to runtime generator
wavefunction91 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,127 @@ | ||
| #include <integratorxx/util/lambert_w.hpp> | ||
| #include <integratorxx/quadratures/radial/radial_transform.hpp> | ||
|
|
||
| namespace IntegratorXX { | ||
| namespace lmg { | ||
|
|
||
| // Eq 19 of LMG paper (DOI 10.1007/s002140100263) | ||
| inline double r_upper_obj(int m, double alpha, double r) { | ||
| const double am_term = (m + 1.0) / 2.0; | ||
| const double g_term = std::tgamma((m + 3.0) / 2.0); | ||
| const double x = alpha * r * r; | ||
| return g_term * std::pow(x, am_term) * std::exp(-x); | ||
wavefunction91 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| // Solve Eq 19 of LMG paper (DOI 10.1007/s002140100263) | ||
| inline double r_upper(int m, double alpha, double prec) { | ||
| // P = G * (ALPHA * R^2)^((M+1)/2) * EXP(-ALPHA * R^2) | ||
| // P = G * X^L * EXP(-X): X = ALPHA * R^2, L = (M+1)/2 | ||
| // X = -L * LAMBERT_W( - (P/G)^(1/L) / L ) | ||
| // R = SQRT(X / ALPHA) | ||
wavefunction91 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| const double am_term = (m + 1.0) / 2.0; | ||
| const double g_term = std::tgamma((m + 3.0) / 2.0); | ||
| const double arg = std::pow(prec/g_term, 1.0 / am_term) / am_term; | ||
| const double wval = lambert_wm1(-arg); // W_(-1) is the larger value here | ||
| const double x = -am_term * wval; | ||
| const double r = std::sqrt(x / alpha); | ||
| return r; | ||
| } | ||
|
|
||
| // Solve Eq 25 of LMG paper (DOI 10.1007/s002140100263) | ||
| inline double r_lower(int m, double alpha, double prec) { | ||
| // Magic numbers below Eq. 25 | ||
| double Dm; | ||
| switch(m) { | ||
| case -2: | ||
| Dm = 9.1; | ||
| break; | ||
| case 0: | ||
| Dm = 1.9; | ||
| break; | ||
| case 2: | ||
| Dm = -1.0; | ||
| break; | ||
| case 4: | ||
| Dm = -2.3; | ||
| break; | ||
| default: | ||
| // Not in the paper, taken from source provided by Roland Lindh | ||
| Dm = 4.0; | ||
| } | ||
|
|
||
| return std::exp(1.0 / (m + 3.0) * (Dm - std::log(1.0 / prec))) / | ||
| std::sqrt(alpha); | ||
| } | ||
|
|
||
| // Eqs 17 and 18 of the LMG paper (DOI 10.1007/s002140100263) | ||
| inline double step_size(int m, double prec) { | ||
|
|
||
| // Recast Eqs 17/18 into the form | ||
| // R == C * x^L * EXP[-PI/2 * X] with X == PI/h | ||
| // X = - 2*L / PI * LAMBERT_W( -PI/(2*L) * (R/C)^(1/L) ) | ||
| double C = 4 * M_SQRT2 * std::tgamma(1.5) / std::tgamma(m / 2.0 + 1.5); | ||
| double L = m / 2.0 + 1.0; // Eq 17 -> Eq 18 | ||
|
|
||
| const double L_FAC = M_PI_2 / L; | ||
| const double X = -(1.0 / L_FAC) * lambert_wm1( -L_FAC * std::pow(prec/C, 1/L)); | ||
| return M_PI / X; | ||
|
|
||
| } | ||
|
|
||
| } | ||
|
|
||
|
|
||
| class LindhMalmqvistGagliardiRadialTraits { | ||
| using self_type = LindhMalmqvistGagliardiRadialTraits; | ||
|
|
||
| double step_size_; | ||
| double c_; | ||
|
|
||
| public: | ||
|
|
||
| LindhMalmqvistGagliardiRadialTraits(double c, double step_size) : | ||
| step_size_(step_size), c_(c) { } | ||
|
|
||
| LindhMalmqvistGagliardiRadialTraits(const self_type&) = default; | ||
| self_type& operator=(const self_type&) = default; | ||
|
|
||
|
|
||
| template <typename PointType> | ||
| inline auto radial_transform(PointType x) const noexcept { | ||
| return c_ * (std::exp(x) - 1.0); | ||
| } | ||
|
|
||
| template <typename PointType> | ||
| inline auto radial_jacobian(PointType x) const noexcept { | ||
| return c_ * std::exp(x); | ||
| } | ||
|
|
||
| template <typename BaseQuad> | ||
| std::enable_if_t< | ||
| // LMG really only makes sense with a Trapezoid grid | ||
| std::is_same_v< | ||
| BaseQuad, | ||
| UniformTrapezoid<typename BaseQuad::point_type, | ||
| typename BaseQuad::weight_type> | ||
| > | ||
| > preprocess_base_quad(typename BaseQuad::point_container& points, | ||
| typename BaseQuad::weight_container& weights) const { | ||
|
|
||
| using point_type = typename BaseQuad::point_type; | ||
| assert(points.size() > 2); | ||
| const auto npts = points.size() - 2; | ||
| point_type up = npts * step_size_; | ||
|
|
||
| // Scale points and weights | ||
| for(auto& x : points ) x *= step_size_ * (npts + 1); | ||
| for(auto& w : weights) w = step_size_; | ||
| } | ||
|
|
||
| }; | ||
|
|
||
| template <typename PointType, typename WeightType> | ||
| using LindhMalmqvistGagliardi = RadialTransformQuadrature< | ||
| UniformTrapezoid<PointType, WeightType>, LindhMalmqvistGagliardiRadialTraits | ||
| >; | ||
|
|
||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| #pragma once | ||
| #include <cmath> | ||
| #include <iostream> | ||
|
|
||
| namespace IntegratorXX { | ||
|
|
||
| // Newton-Raphson implementation of Lambert-W function for real arguments | ||
| template <typename RealType> | ||
| RealType lambert_w_newton(RealType x, RealType w0) { | ||
|
|
||
| const auto eps = std::numeric_limits<RealType>::epsilon(); | ||
| const size_t max_iter = 100000; | ||
| RealType w; | ||
| size_t i; | ||
| for(i = 0; i < max_iter; ++i) { | ||
| const auto exp_term = std::exp(w0); | ||
| const auto w_exp_term = w0 * exp_term; | ||
| w = w0 - (w_exp_term - x) / (exp_term + w_exp_term); | ||
| if(std::abs(w - w0) < eps) break; | ||
| w0 = w; | ||
| } | ||
|
|
||
| return w; | ||
| } | ||
|
|
||
| template< typename RealType> | ||
| RealType lambert_w0(RealType x) { | ||
| const RealType one = 1; | ||
| const auto e = std::exp(one); | ||
| if(x < -one/e) return std::numeric_limits<RealType>::quiet_NaN(); | ||
| if(x == RealType(0)) return 0.0; | ||
| if(x == -one/e) return -1.0; | ||
|
|
||
| RealType w0; | ||
| if(x > e) { | ||
| w0 = std::log(x) - std::log(std::log(x)); | ||
| } else if(x > 0.0) { | ||
| w0 = x / e; | ||
| } else { | ||
| const auto xe = x * e; | ||
| const auto sqrt_term = std::sqrt(1.0 + xe); | ||
| w0 = xe * std::log(1.0 + sqrt_term) / (1.0 + xe + sqrt_term); | ||
| } | ||
|
|
||
| return lambert_w_newton(x, w0); | ||
|
|
||
| } | ||
|
|
||
| template< typename RealType> | ||
| RealType lambert_wm1(RealType x) { | ||
| const RealType one = 1; | ||
| const auto e = std::exp(one); | ||
| if(x < -one/e) return std::numeric_limits<RealType>::quiet_NaN(); | ||
| if(x >= RealType(0)) return std::numeric_limits<RealType>::infinity(); | ||
| if(x == -one/e) return -1.0; | ||
|
|
||
| RealType wm1; | ||
| if(x > -0.25) { | ||
| wm1 = std::log(-x) - std::log(-std::log(-x)); | ||
| } else { | ||
| wm1 = -1.0 - std::sqrt(2.0*(1.0 + x * e)); | ||
| } | ||
|
|
||
| return lambert_w_newton(x, wm1); | ||
|
|
||
| } | ||
|
|
||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.