evaleev / libint

Libint: high-performance library for computing Gaussian integrals in quantum mechanics
Other
218 stars 97 forks source link

Accuracy of FmEval_Taylor #241

Closed bingao closed 2 years ago

bingao commented 2 years ago

Hi,

I downloaded Libint 2.7.1 at https://github.com/evaleev/libint/releases/download/v2.7.1/libint-2.7.1.tgz and tried to use it for the calculation of Boys functions. I notice that there are a few evaluators to choose. Anyway, I wonder about the accuracy of FmEval_Taylor. I used FmEval_Taylor<double,7> to evaluate mmax=20 and T=33.50904838850329. I got the 20th order Boys function Fm(20)=1.4334837325143516e-14. But the more accurate value is 1.456420846120653e-14.

So I wonder about what the limitation is for the use of FmEval_Taylor? Thank you.

P.S. I used GCC 11.2.0 and built Libint as Release type.

evaleev commented 2 years ago

@bingao could you share more details please. I have tested the Taylor-based engine and do not see any issues

m=20 T=3.350905e+01 ref_value=1.456421e-14 value==1.456421e-14 abs_error=7.835090e-30 relabs_error=5.379688e-16
m

But this is on a Mac with Apple clang, Debug, etc.

The recommended engine is FmEval_Chebyshev7, which on x86 uses intrinsics to produce vectorized code.

P.S. For the Boys engine only absolute precision can be guaranteed practically, but for most practical T,m combinations almost max relative precision is attained.

evaleev commented 2 years ago

Dear @bingao:

OK, tried your code with gcc on an Arm-based Mac, still no errors. This might be an issue with the x86-specific code. Will dig in deeper.

Thanks for the report.

What level of precision are you looking for?

Ed

On Fri, Mar 11, 2022 at 10:22 AM Bin Gao @.***> wrote:

Hi @evaleev https://github.com/evaleev sorry I forgot to post more details. I built Libint without C++11 and Fortran03+ interfaces (so Eigen3 is not used). The compiler flag is quite simple:

g++ -D__COMPILING_LIBINT2 -I/cluster/home/gaobin/libint-2.7.1/include -I/cluster/home/gaobin/libint-2.7.1/build/include -O3 -DNDEBUG -MD -MT

I have used FmEval_Chebyshev7 which is very fast and accurate. A maximum relative error 6e-15 is obtained in my tests, with mmax as 10, 20, 30, 40, and different 100,000 T's.

However, FmEval_Taylor<double,7> gave me a bit inaccurate results as shown in my last post. The source code of testing FmEval_Taylor<double,7> is:

include

include

include

include

include <libint2/boys.h>

if !LIBINT2_CONSTEXPR_STATICS

include <libint2/statics_definition.h>

endif

include <libint2/initialize.h>

int main() { LIBINT2_PREFIXED_NAME(libint2_static_init)(); const int num_args = 100000; / I use Chebyshev nodes as different T's / double vmin = 0.0; double vmax = 5000.0; double step_angle = 3.141592653589793/num_args; double sum_ab = 0.5(vmax+vmin); double diff_ab = 0.5(vmax-vmin); std::vector args(num_args, 0.0); for (int iarg=0; iarg<num_args; ++iarg) { args[iarg] = sum_ab+diff_abstd::cos((iarg+0.5)step_angle); } std::ofstream fboys; for (int mmax=10; mmax<=60; mmax+=10) { auto vals = new double[mmax+1]; libint2::FmEval_Taylor fm_eval(mmax); / Write computed Boys functions into a file and verify their accuracy afterwards. / fboys.open("boys_vals.txt"); fboys << std::setprecision(17); fboys << std::scientific; for (int iarg=0; iarg<num_args; ++iarg) { fm_eval.eval(vals, args[iarg], mmax); fboys << args[iarg] << "\n"; for (int ival=0; ival<=mmax; ++ival) { fboys << vals[ival] << ", "; } fboys << "\n"; } fboys.close(); delete[] vals; } LIBINT2_PREFIXED_NAME(libint2_static_cleanup)(); return 0; }

I compiled the above code as:

g++ -D__COMPILING_LIBINT2 -I/cluster/home/gaobin/libint-2.7.1/include -I/cluster/home/gaobin/libint-2.7.1/build/include -I/cluster/home/gaobin/libint-2.7.1/build/include/libint2 -O3 -DNDEBUG test_FmEval.cpp libint2.a

I know there is a highly accurate reference evaluator available in Libint. But I prepared an evaluator of Boys functions in Python by using mpmath ( https://mpmath.org). So after running the above tests, I compared computed Boys functions to those obtained from mpmath.

I hope I have written all details of my testing. Did I do something wrong in the above testing code? Thank you for your kind help. Have a nice weekend.

— Reply to this email directly, view it on GitHub https://github.com/evaleev/libint/issues/241#issuecomment-1065212623, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAQXIZ6VZV36FAGWEWFT4UDU7NQJ3ANCNFSM5QBSVMVQ . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.

You are receiving this because you were mentioned.Message ID: @.***>

-- web: valeyev.net

bingao commented 2 years ago

Hi @evaleev sorry I forgot to post more details. I built Libint without C++11 and Fortran03+ interfaces (so Eigen3 is not used). The compiler flag is quite simple:

g++ -D__COMPILING_LIBINT2 -I/cluster/home/gaobin/libint-2.7.1/include -I/cluster/home/gaobin/libint-2.7.1/build/include -O3 -DNDEBUG -MD -MT

I have used FmEval_Chebyshev7 which is very fast and accurate. A maximum relative error 6e-15 is obtained in my tests, with mmax as 10, 20, 30, 40, and different 100,000 T's.

However, FmEval_Taylor<double,7> gave me a bit inaccurate or strange results that I will explain below. First, the source code (named as test_FmEval.cpp) of testing FmEval_Taylor<double,7> is:

#include <cmath>
#include <iomanip>
#include <stream>
#include <string>

#include <libint2.h>
#include <libint2/boys.h>
#if !LIBINT2_CONSTEXPR_STATICS
#  include <libint2/statics_definition.h>
#endif
#include <libint2/initialize.h>

int main()
{
    LIBINT2_PREFIXED_NAME(libint2_static_init)();
    const int num_args = 100000;
    /* I use Chebyshev nodes as different T's */
    double vmin = 0.0;
    double vmax = 5000.0;
    double step_angle = 3.141592653589793/num_args;
    double sum_ab = 0.5*(vmax+vmin);
    double diff_ab = 0.5*(vmax-vmin);
    std::vector<double> args(num_args, 0.0);
    for (int iarg=0; iarg<num_args; ++iarg) {
        args[iarg] = sum_ab+diff_ab*std::cos((iarg+0.5)*step_angle);
    }
    std::ofstream fboys;
    for (int mmax=10; mmax<=60; mmax+=10) {
        auto vals = new double[mmax+1];
        libint2::FmEval_Taylor<double> fm_eval(mmax);
        /* Write computed Boys functions into a file and verify their accuracy afterwards. */
        fboys.open("boys_vals_"+std::to_string(mmax)+".txt");
        fboys << std::setprecision(17);
        fboys << std::scientific;
        for (int iarg=0; iarg<num_args; ++iarg) {
            fm_eval.eval(vals, args[iarg], mmax);
            fboys << args[iarg] << "\n";
            for (int ival=0; ival<=mmax; ++ival) {
                fboys << vals[ival] << ", ";
            }
            fboys << "\n";
        }
        fboys.close();
        delete[] vals;
    }
    LIBINT2_PREFIXED_NAME(libint2_static_cleanup)();
    return 0;
}

I compiled the above code as:

g++ -D__COMPILING_LIBINT2 -I/cluster/home/gaobin/libint-2.7.1/include -I/cluster/home/gaobin/libint-2.7.1/build/include -I/cluster/home/gaobin/libint-2.7.1/build/include/libint2 -O3 -DNDEBUG test_FmEval.cpp libint2.a

I know there is a highly accurate reference evaluator available in Libint. But I prepared an evaluator of Boys functions in Python by using mpmath (https://mpmath.org). So after running the above tests, I compared computed Boys functions to those obtained from mpmath.

For mmax=20 and T=3.35090483885032882e+01, I got (the first line is T):

3.35090483885032882e+01
1.53096017450543687e-01, 2.28439816725841457e-03, 1.02258864864150114e-04, 7.62919791678374625e-06, 7.96865145132092385e-07, 1.07012682369235934e-07, 1.75645021251209397e-08, 3.40711741764366456e-09, 7.62581465636089048e-10, 1.93438529874176702e-10, 5.48408481299377374e-11, 1.71842392698288492e-11, 5.89743251314769462e-12, 2.19989852912697362e-12, 8.86245101528155682e-13, 3.83453259285439483e-13, 1.77328979862341899e-13, 8.72757704661901120e-14, 4.55377250178399760e-14, 2.50991240051276858e-14, 1.43348373251435156e-14,

The 20th order Boys function Fm(20)=1.43348373251435156e-14. When I used mmax=30, the results are:

3.35090483885032882e+01
1.53096017450543687e-01, 2.28439816725841457e-03, 1.02258864864150114e-04, 7.62919791678374625e-06, 7.96865145132092385e-07, 1.07012682369235934e-07, 1.75645021251209397e-08, 3.40711741764366456e-09, 7.62581465636089048e-10, 1.93438529874176702e-10, 5.48408481299377374e-11, 1.71842392698288492e-11, 5.89743251314769462e-12, 2.19989852912697362e-12, 8.86245101528155682e-13, 3.83453259285439483e-13, 1.77328979862341899e-13, 8.72757704661901120e-14, 4.55377250178399760e-14, 2.50991240051276858e-14, 1.45642084612065371e-14, 8.86823516968384032e-15, 5.64823273763774357e-15, 3.75078047894668816e-15, 2.58864973473364547e-15, 1.85089608480443712e-15, 1.36672631219974662e-15, 1.03906547379208609e-15, 8.10949573412370265e-16, 6.47941730763401423e-16, 2.99266049301716253e-16,

The 20th order Boys function becomes more accurate, as Fm(20)=1.45642084612065371e-14.

It seems that the last element of computed Boys functions is not accurate, a bit strange to me.

I hope I have written all details of my testing. Did I do something wrong in the above testing code? Thank you for your kind help. Have a nice weekend.

evaleev commented 2 years ago

Ah, OK, now reproduced on a mac. I think I understand the issue.

On Fri, Mar 11, 2022 at 1:19 PM Bin Gao @.***> wrote:

Hi @evaleev https://github.com/evaleev sorry I forgot to post more details. I built Libint without C++11 and Fortran03+ interfaces (so Eigen3 is not used). The compiler flag is quite simple:

g++ -D__COMPILING_LIBINT2 -I/cluster/home/gaobin/libint-2.7.1/include -I/cluster/home/gaobin/libint-2.7.1/build/include -O3 -DNDEBUG -MD -MT

I have used FmEval_Chebyshev7 which is very fast and accurate. A maximum relative error 6e-15 is obtained in my tests, with mmax as 10, 20, 30, 40, and different 100,000 T's.

However, FmEval_Taylor<double,7> gave me a bit inaccurate or strange results that I will explain below. First, the source code (named as test_FmEval.cpp) of testing FmEval_Taylor<double,7> is:

include

include

include

include

include

include <libint2/boys.h>

if !LIBINT2_CONSTEXPR_STATICS

include <libint2/statics_definition.h>

endif

include <libint2/initialize.h>

int main() { LIBINT2_PREFIXED_NAME(libint2_static_init)(); const int num_args = 100000; / I use Chebyshev nodes as different T's / double vmin = 0.0; double vmax = 5000.0; double step_angle = 3.141592653589793/num_args; double sum_ab = 0.5(vmax+vmin); double diff_ab = 0.5(vmax-vmin); std::vector args(num_args, 0.0); for (int iarg=0; iarg<num_args; ++iarg) { args[iarg] = sum_ab+diff_abstd::cos((iarg+0.5)step_angle); } std::ofstream fboys; for (int mmax=10; mmax<=60; mmax+=10) { auto vals = new double[mmax+1]; libint2::FmEval_Taylor fm_eval(mmax); / Write computed Boys functions into a file and verify their accuracy afterwards. / fboys.open("boysvals"+std::to_string(mmax)+".txt"); fboys << std::setprecision(17); fboys << std::scientific; for (int iarg=0; iarg<num_args; ++iarg) { fm_eval.eval(vals, args[iarg], mmax); fboys << args[iarg] << "\n"; for (int ival=0; ival<=mmax; ++ival) { fboys << vals[ival] << ", "; } fboys << "\n"; } fboys.close(); delete[] vals; } LIBINT2_PREFIXED_NAME(libint2_static_cleanup)(); return 0; }

I compiled the above code as:

g++ -D__COMPILING_LIBINT2 -I/cluster/home/gaobin/libint-2.7.1/include -I/cluster/home/gaobin/libint-2.7.1/build/include -I/cluster/home/gaobin/libint-2.7.1/build/include/libint2 -O3 -DNDEBUG test_FmEval.cpp libint2.a

I know there is a highly accurate reference evaluator available in Libint. But I prepared an evaluator of Boys functions in Python by using mpmath ( https://mpmath.org). So after running the above tests, I compared computed Boys functions to those obtained from mpmath.

For mmax=20 and T=3.35090483885032882e+01, I got (the first line is T):

3.35090483885032882e+01 1.53096017450543687e-01, 2.28439816725841457e-03, 1.02258864864150114e-04, 7.62919791678374625e-06, 7.96865145132092385e-07, 1.07012682369235934e-07, 1.75645021251209397e-08, 3.40711741764366456e-09, 7.62581465636089048e-10, 1.93438529874176702e-10, 5.48408481299377374e-11, 1.71842392698288492e-11, 5.89743251314769462e-12, 2.19989852912697362e-12, 8.86245101528155682e-13, 3.83453259285439483e-13, 1.77328979862341899e-13, 8.72757704661901120e-14, 4.55377250178399760e-14, 2.50991240051276858e-14, 1.43348373251435156e-14,

The 20th order Boys function Fm(20)=1.43348373251435156e-14. When I used mmax=30, the results are:

3.35090483885032882e+01 1.53096017450543687e-01, 2.28439816725841457e-03, 1.02258864864150114e-04, 7.62919791678374625e-06, 7.96865145132092385e-07, 1.07012682369235934e-07, 1.75645021251209397e-08, 3.40711741764366456e-09, 7.62581465636089048e-10, 1.93438529874176702e-10, 5.48408481299377374e-11, 1.71842392698288492e-11, 5.89743251314769462e-12, 2.19989852912697362e-12, 8.86245101528155682e-13, 3.83453259285439483e-13, 1.77328979862341899e-13, 8.72757704661901120e-14, 4.55377250178399760e-14, 2.50991240051276858e-14, 1.45642084612065371e-14, 8.86823516968384032e-15, 5.64823273763774357e-15, 3.75078047894668816e-15, 2.58864973473364547e-15, 1.85089608480443712e-15, 1.36672631219974662e-15, 1.03906547379208609e-15, 8.10949573412370265e-16, 6.47941730763401423e-16, 2.99266049301716253e-16,

The 20th order Boys function becomes more accurate, as Fm(20)=1.45642084612065371e-14.

It seems that the last element of computed Boys functions is not accurate, a bit strange to me.

I hope I have written all details of my testing. Did I do something wrong in the above testing code? Thank you for your kind help. Have a nice weekend.

— Reply to this email directly, view it on GitHub https://github.com/evaleev/libint/issues/241#issuecomment-1065366447, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAQXIZ6TSBNTRMBOUUYPHVLU7OFCBANCNFSM5QBSVMVQ . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.

You are receiving this because you were mentioned.Message ID: @.***>

-- web: valeyev.net

bingao commented 2 years ago

Hi @evaleev I ran Libint and my testing code on one Norwegian supercomputer (https://documentation.sigma2.no/hpc_machines/betzy.html) whose CPU type is AMD® Epyc™ 7742 2.25GHz and has Red Hat Enterprise Linux 7.

Actually, I am benchmarking my Boy function evaluator against Libint. My evaluator focuses on error control with a wide range of orders and arguments, but for sure is slower than Libint.

Thank you for your kind help.

evaleev commented 2 years ago

@bingao should be fixed, to test you have to apply 9e92fad0b085aeab275bce51c7c212c624dd55d2 manually

evaleev commented 2 years ago

@bingao I would be interested in learning which argument values do not produce sufficient precision .... Last revision of the Boys engine greatly increased its implicit precision, but clearly there are use cases still where the precision is not sufficient?