21#ifndef _libint2_src_lib_libint_boys_h_
22#define _libint2_src_lib_libint_boys_h_
24#if defined(__cplusplus)
30#include <libint2/util/vector.h>
40#include <libint2/util/cxxstd.h>
41#if LIBINT2_CPLUSPLUS_STD < 2011
42# error "Libint2 C++ API requires C++11 support"
45#include <libint2/boys_fwd.h>
46#include <libint2/numeric.h>
47#include <libint2/initialize.h>
50extern "C" void dgesv_(
const int* n,
51 const int* nrhs,
double* A,
const int* lda,
52 int* ipiv,
double* b,
const int* ldb,
59 template<
typename Real>
66 for (
int i = 1; i <= ifac; i++) {
67 fac[i] = i * fac[i - 1];
79 for (
int i = 3; i <= idf; i++) {
80 df[i] = (i - 1) * df[i - 2];
85 bc_.resize((ibc+1)*(ibc+1));
86 std::fill(bc_.begin(), bc_.end(), Real(0));
89 for(
int i=1; i<=ibc; ++i)
90 bc[i] = bc[i-1] + (ibc+1);
92 for(
int i=0; i<=ibc; i++)
94 for(
int i=0; i<=ibc; i++)
95 for(
int j=1; j<=i; ++j)
96 bc[i][j] = bc[i][j-1] * Real(i-j+1) / Real(j);
99 for (
int i = 0; i < 128; i++) {
100 twoi1[i] = 1.0 / (Real(2.0) * i + Real(1.0));
101 ihalf[i] = Real(i) - Real(0.5);
109 std::vector<Real> fac;
110 std::vector<Real> df;
111 std::vector<Real*> bc;
120 std::vector<Real> bc_;
141 template<
typename Real>
144 static std::shared_ptr<const FmEval_Reference> instance(
int , Real ) {
147 static auto instance_ = std::make_shared<const FmEval_Reference>();
153 static Real
eval(Real T,
size_t m) {
155 static const Real T_crit = std::numeric_limits<Real>::is_bounded ? -log( std::numeric_limits<Real>::min() * 100.5 / 2. ) : Real(0) ;
156 if (std::numeric_limits<Real>::is_bounded && T > T_crit)
157 throw std::overflow_error(
"FmEval_Reference<Real>::eval: Real lacks precision for the given value of argument T");
158 static const Real half = Real(1)/2;
159 Real denom = (m + half);
161 Real term = exp(-T) / (2 * denom);
164 const Real epsilon = get_epsilon(T);
165 const Real epsilon_divided_10 = epsilon / 10;
169 term = old_term * T / denom;
173 }
while (term > sum * epsilon_divided_10 || old_term < term);
182 static void eval(Real* Fm, Real T,
size_t mmax) {
187 for(
size_t m=0; m<=mmax; ++m)
204 template<
typename Real>
207 static std::shared_ptr<const FmEval_Reference2> instance(
int , Real ) {
210 static auto instance_ = std::make_shared<const FmEval_Reference2>();
219 static void eval(Real* Fm, Real t,
size_t mmax) {
225 const Real two_over_sqrt_pi{1.128379167095512573896158903121545171688101258657997713688171443421284936882986828973487320404214727};
226 const Real K = 1/two_over_sqrt_pi;
230 auto sqrt_t = sqrt(t);
231 Fm[0] = K*erf(sqrt_t)/sqrt_t;
233 for(
size_t m=0; m<=mmax-1; m++) {
234 Fm[m+1] = ((2*m + 1)*Fm[m] - et)/(t2);
244 template <
typename Real =
double>
247#include <libint2/boys_cheb7.h>
249 static_assert(std::is_same<Real,double>::value,
"FmEval_Chebyshev7 only supports double as the real type");
251 static constexpr int ORDER = interpolation_order;
252 static constexpr int ORDERp1 = ORDER+1;
254 static constexpr Real T_crit = cheb_table_tmax;
255 static constexpr Real delta = cheb_table_delta;
256 static constexpr Real one_over_delta = 1/delta;
268 mmax(m_max), numbers_(14) {
269#if defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86)
270# if !defined(__AVX__) && defined(NDEBUG)
272 static bool printed_performance_warning =
false;
273 if (!printed_performance_warning) {
275 <<
"libint2::FmEval_Chebyshev7 on x86(-64) platforms needs AVX support for best performance"
277 printed_performance_warning =
true;
282 if (precision < std::numeric_limits<double>::epsilon())
283 throw std::invalid_argument(std::string(
"FmEval_Chebyshev7 does not support precision smaller than ") + std::to_string(std::numeric_limits<double>::epsilon()));
284 if (mmax > cheb_table_mmax)
285 throw std::invalid_argument(
286 "FmEval_Chebyshev7::init() : requested mmax exceeds the "
298 static std::shared_ptr<const FmEval_Chebyshev7>
instance(
int m_max,
double = 0.0) {
302 static auto instance_ = std::make_shared<const FmEval_Chebyshev7>(m_max);
304 while (instance_->max_m() < m_max) {
305 static std::mutex mtx;
306 std::lock_guard<std::mutex> lck(mtx);
307 if (instance_->max_m() < m_max) {
308 auto new_instance = std::make_shared<const FmEval_Chebyshev7>(m_max);
309 instance_ = new_instance;
323 inline void eval(Real* Fm, Real x,
int m_max)
const {
328 const double one_over_x = 1/x;
329 Fm[0] = 0.88622692545275801365 * sqrt(one_over_x);
333 for (
int i = 1; i <= m_max; i++)
334 Fm[i] = Fm[i - 1] * numbers_.ihalf[i] * one_over_x;
342 const Real x_over_delta = x * one_over_delta;
343 const int iv = int(x_over_delta);
344 const Real xd = x_over_delta - (Real)iv - 0.5;
348 const auto x2 = xd*xd;
349 const auto x3 = x2*xd;
350 const auto x4 = x2*x2;
351 const auto x5 = x2*x3;
352 const auto x6 = x3*x3;
353 const auto x7 = x3*x4;
358 const Real *d = c + (ORDERp1) * (iv * (mmax+1) + m_min);
362 const int unroll_size = 4;
363 const int m_fence = (m_max + 2 - unroll_size);
364 for(; m<m_fence; m+=unroll_size, d+=ORDERp1*unroll_size) {
366 d20v, d21v, d30v, d31v;
380 const int unroll_size = 2;
381 const int m_fence = (m_max + 2 - unroll_size);
382 for(; m<m_fence; m+=unroll_size, d+=ORDERp1*unroll_size) {
395 for(; m<=m_max; ++m, d+=ORDERp1) {
399 Fm[m] = horizontal_add(d0v * x0vec + d1v * x1vec);
403 for(m=m_min; m<=m_max; ++m, d+=ORDERp1) {
433 int status = posix_memalign(&result, ORDERp1*
sizeof(Real), (mmax + 1) * cheb_table_nintervals * ORDERp1 *
sizeof(Real));
435 if (status == EINVAL)
436 throw std::logic_error(
437 "FmEval_Chebyshev7::init() : posix_memalign failed, alignment must be a power of 2 at least as large as sizeof(void *)");
438 if (status == ENOMEM)
439 throw std::bad_alloc();
442 c =
static_cast<Real*
>(result);
446 for (std::size_t iv = 0; iv < cheb_table_nintervals; ++iv) {
448 std::copy(cheb_table[iv], cheb_table[iv]+(mmax+1)*ORDERp1, c+(iv*(mmax+1))*ORDERp1);
454#if LIBINT2_CONSTEXPR_STATICS
455 template <
typename Real>
457 double FmEval_Chebyshev7<Real>::cheb_table[FmEval_Chebyshev7<Real>::cheb_table_nintervals][(FmEval_Chebyshev7<Real>::cheb_table_mmax+1)*(FmEval_Chebyshev7<Real>::interpolation_order+1)];
461 template <
typename Real>
462 double FmEval_Chebyshev7<Real>::cheb_table[FmEval_Chebyshev7<Real>::cheb_table_nintervals][(FmEval_Chebyshev7<Real>::cheb_table_mmax+1)*(FmEval_Chebyshev7<Real>::interpolation_order+1)];
469 const double oon[] = {0.0, 1.0, 1.0/2.0, 1.0/3.0, 1.0/4.0, 1.0/5.0, 1.0/6.0, 1.0/7.0, 1.0/8.0, 1.0/9.0, 1.0/10.0, 1.0/11.0};
478 template<
typename Real =
double,
int INTERPOLATION_ORDER = 7>
481 static_assert(std::is_same<Real,double>::value,
"FmEval_Taylor only supports double as the real type");
483 static const int max_interp_order = 8;
484 static const bool INTERPOLATION_AND_RECURSION =
false;
485 const double soft_zero_;
489 soft_zero_(1e-6), cutoff_(
precision), numbers_(
490 INTERPOLATION_ORDER + 1, 2 * (mmax + INTERPOLATION_ORDER)) {
492#if defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86)
493# if !defined(__AVX__) && defined(NDEBUG)
495 static bool printed_performance_warning =
false;
496 if (!printed_performance_warning) {
498 <<
"libint2::FmEval_Taylor on x86(-64) platforms needs AVX support for best performance"
500 printed_performance_warning =
true;
508 const double sqrt_pi = std::sqrt(M_PI);
516 * std::pow(cutoff_ * numbers_.fac[INTERPOLATION_ORDER + 1],
517 1.0 / INTERPOLATION_ORDER);
518 oodelT_ = 1.0 / delT_;
519 max_m_ = mmax + INTERPOLATION_ORDER;
521 T_crit_ =
new Real[max_m_ + 1];
524 for (
int m = max_m_; m >= 0; --m) {
531 double T = -log(cutoff_);
532 const double egamma = cutoff_ * sqrt_pi * numbers_.df[2 * m]
537 const double damping_factor = 0.2;
540 func = std::pow(T, m - 0.5) * std::exp(-T) - egamma;
541 const double dfuncdT = ((m - 0.5) * std::pow(T, m - 1.5)
542 - std::pow(T, m - 0.5)) * std::exp(-T);
548 double deltaT = -func / dfuncdT;
549 const double sign_deltaT = (deltaT > 0.0) ? 1.0 : -1.0;
550 const double max_deltaT = damping_factor * T;
551 if (std::fabs(deltaT) > max_deltaT)
552 deltaT = sign_deltaT * max_deltaT;
558 }
while (std::fabs(func / egamma) >= soft_zero_);
560 const int T_idx = (int) std::floor(T_new / delT_);
561 max_T_ = std::max(max_T_, T_idx);
566 const int nrow = max_T_ + 1;
567 const int ncol = max_m_ + 1;
568 grid_ =
new Real*[nrow];
569 grid_[0] =
new Real[nrow * ncol];
571 for (
int r = 1; r < nrow; ++r)
572 grid_[r] = grid_[r - 1] + ncol;
581 for (
int T_idx = max_T_; T_idx >= 0; --T_idx) {
582 const double T = T_idx * delT_;
595 static std::shared_ptr<const FmEval_Taylor>
instance(
unsigned int mmax, Real
precision = std::numeric_limits<Real>::epsilon()) {
599 static auto instance_ = std::make_shared<const FmEval_Taylor>(mmax,
precision);
601 while (instance_->max_m() < mmax || instance_->precision() >
precision) {
602 static std::mutex mtx;
603 std::lock_guard<std::mutex> lck(mtx);
604 if (instance_->max_m() < mmax || instance_->precision() >
precision) {
605 auto new_instance = std::make_shared<const FmEval_Taylor>(mmax,
precision);
606 instance_ = new_instance;
614 int max_m()
const {
return max_m_ - INTERPOLATION_ORDER + 1; }
623 void eval(Real* Fm, Real T,
int mmax)
const {
624 const double sqrt_pio2 = 1.2533141373155002512;
625 const double two_T = 2.0 * T;
628 const int mmin = INTERPOLATION_AND_RECURSION ? mmax : 0;
632 const bool use_upward_recursion =
true;
633 if (use_upward_recursion) {
635 if (T > T_crit_[0]) {
636 const double one_over_x = 1.0/T;
637 Fm[0] = 0.88622692545275801365 * sqrt(one_over_x);
641 for (
int i = 1; i <= mmax; i++)
642 Fm[i] = Fm[i - 1] * numbers_.ihalf[i] * one_over_x;
648 if (T > T_crit_[mmax]) {
649 double pow_two_T_to_minusjp05 = std::pow(two_T, -mmax - 0.5);
650 for (
int m = mmax; m >= mmin; --m) {
652 Fm[m] = numbers_.df[2 * m] * sqrt_pio2 * pow_two_T_to_minusjp05;
653 pow_two_T_to_minusjp05 *= two_T;
658 const int T_ind = (int) (0.5 + T * oodelT_);
659 const Real h = T_ind * delT_ - T;
660 const Real* F_row = grid_[T_ind] + mmin;
664 if (INTERPOLATION_ORDER == 3 || INTERPOLATION_ORDER == 7) {
665 const double h2 = h*h*oon[2];
666 const double h3 = h2*h*oon[3];
668 if (INTERPOLATION_ORDER == 7) {
669 const double h4 = h3*h*oon[4];
670 const double h5 = h4*h*oon[5];
671 const double h6 = h5*h*oon[6];
672 const double h7 = h6*h*oon[7];
682 const int unroll_size = 2;
683 const int m_fence = (mmax + 2 - unroll_size);
684 for(; m<m_fence; m+=unroll_size, F_row+=unroll_size) {
687 if (INTERPOLATION_ORDER == 3 || INTERPOLATION_ORDER == 7) {
691 if (INTERPOLATION_ORDER == 7) {
694 fm01 += horizontal_add(fr0_4567*h4567, fr1_4567*h4567);
700 Real total0 = 0.0, total1 = 0.0;
701 for(
int i=INTERPOLATION_ORDER; i>=1; --i) {
702 total0 = oon[i]*h*(F_row[i] + total0);
703 total1 = oon[i]*h*(F_row[i+1] + total1);
705 Fm[m] = F_row[0] + total0;
706 Fm[m+1] = F_row[1] + total1;
714 if (INTERPOLATION_ORDER == 3 || INTERPOLATION_ORDER == 7) {
716 if (INTERPOLATION_ORDER == 7) {
720 Fm[m] = horizontal_add(fr0123*h0123 + fr4567*h4567);
723 Fm[m] = horizontal_add(fr0123*h0123);
729 for(
int i=INTERPOLATION_ORDER; i>=1; --i) {
730 total = oon[i]*h*(F_row[i] + total);
732 Fm[m] = F_row[0] + total;
752 if (INTERPOLATION_AND_RECURSION && mmin > 0) {
753 const Real exp_mT = std::exp(-T);
754 for (
int m = mmin - 1; m >= 0; --m) {
755 Fm[m] = (exp_mT + two_T * Fm[m+1]) * numbers_.twoi1[m];
785 static double truncation_error(
unsigned int m,
double T) {
786 const double m2= m * m;
787 const double m3= m2 * m;
788 const double m4= m2 * m2;
789 const double T2= T * T;
790 const double T3= T2 * T;
791 const double T4= T2 * T2;
792 const double T5= T2 * T3;
794 const double result = exp(-T) * (105 + 16*m4 + 16*m3*(T - 8) - 30*T + 12*T2
795 - 8*T3 + 16*T4 + 8*m2*(43 - 9*T + 2*T2) +
796 4*m*(-88 + 23*T - 8*T2 + 4*T3))/(32*T5);
807 static double truncation_error(
double T) {
808 const double result = exp(-T) /(2*T);
815 constexpr double pow10(
long exp) {
816 return (exp == 0) ? 1. : ((exp > 0) ? 10. * pow10(exp-1) : 0.1 * pow10(exp+1));
831 template<
typename Real =
double>
836 #include <libint2/tenno_cheb.h>
838 static_assert(std::is_same<Real,double>::value,
"TennoGmEval only supports double as the real type");
840 static const int mmin_ = -1;
841 static constexpr Real Tmax = (1 << cheb_table_tmaxlog2);
842 static constexpr Real Umax = detail::pow10(cheb_table_umaxlog10);
843 static constexpr Real Umin = detail::pow10(cheb_table_uminlog10);
844 static constexpr std::size_t ORDERp1 = interpolation_order + 1;
845 static constexpr Real maxabsprecision = 1.4e-14;
855#if defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86)
856# if !defined(__AVX__) && defined(NDEBUG)
858 static bool printed_performance_warning =
false;
859 if (!printed_performance_warning) {
861 <<
"libint2::TennoGmEval on x86(-64) platforms needs AVX support for best performance"
863 printed_performance_warning =
true;
875 if (mmax > cheb_table_mmax)
876 throw std::invalid_argument(
877 "TennoGmEval::init() : requested mmax exceeds the "
888 static std::shared_ptr<const TennoGmEval>
instance(
int m_max,
double = 0) {
892 static auto instance_ = std::make_shared<const TennoGmEval>(m_max);
894 while (instance_->max_m() < m_max) {
895 static std::mutex mtx;
896 std::lock_guard<std::mutex> lck(mtx);
897 if (instance_->max_m() < m_max) {
898 auto new_instance = std::make_shared<const TennoGmEval>(m_max);
899 instance_ = new_instance;
906 unsigned int max_m()
const {
return mmax_; }
920 void eval_yukawa(Real* Gm, Real one_over_rho, Real T,
size_t mmax, Real zeta)
const {
921 assert(mmax <= mmax_);
923 const auto U = 0.25 * zeta * zeta * one_over_rho;
925 if (T > Tmax || U < Umin) {
926 eval_urr<false>(Gm, T, U, 0, mmax);
928 interpolate_Gm<false>(Gm, T, U, 0, mmax);
942 void eval_slater(Real* Gm, Real one_over_rho, Real T,
size_t mmax, Real zeta)
const {
943 assert(mmax <= mmax_);
945 const auto U = 0.25 * zeta * zeta * one_over_rho;
947 const auto zeta_over_two_rho = 0.5 * zeta * one_over_rho;
949 eval_urr<true>(Gm, T, U, zeta_over_two_rho, mmax);
951 interpolate_Gm<true>(Gm, T, U, zeta_over_two_rho, mmax);
962 template <
bool compute_Gm1>
963 static inline std::tuple<Real,Real> eval_G0_and_maybe_Gm1(Real T, Real U) {
966 const Real sqrtPi(1.7724538509055160272981674833411451827975494561224);
971 assert(!compute_Gm1);
972 if (T < std::numeric_limits<Real>::epsilon()) {
976 const Real sqrt_T = sqrt(T);
977 const Real sqrtPi_over_2 = sqrtPi * 0.5;
978 G_0 = sqrtPi_over_2 * erf(sqrt_T) / sqrt_T;
981 else if (T > std::numeric_limits<Real>::epsilon()) {
982 const Real sqrt_U = sqrt(U);
983 const Real sqrt_T = sqrt(T);
984 const Real oo_sqrt_T = 1 / sqrt_T;
985 const Real oo_sqrt_U = compute_Gm1 ? (1 / sqrt_U) : 0;
986 const Real kappa = sqrt_U - sqrt_T;
987 const Real lambda = sqrt_U + sqrt_T;
988 const Real sqrtPi_over_4 = sqrtPi * 0.25;
989 const Real pfac = sqrtPi_over_4;
990 const Real erfc_k = exp(kappa * kappa - T) * erfc(kappa);
991 const Real erfc_l = exp(lambda * lambda - T) * erfc(lambda);
993 G_m1 = compute_Gm1 ? pfac * (erfc_k + erfc_l) * oo_sqrt_U : 0.0;
994 G_0 = pfac * (erfc_k - erfc_l) * oo_sqrt_T;
997 const Real exp_U = exp(U);
998 const Real sqrt_U = sqrt(U);
1000 const Real sqrtPi_over_2 = sqrtPi * 0.5;
1001 const Real oo_sqrt_U = compute_Gm1 ? (1 / sqrt_U) : 0;
1003 G_m1 = exp_U * sqrtPi_over_2 * erfc(sqrt_U) * oo_sqrt_U;
1005 G_0 = 1 - exp_U * sqrtPi * erfc(sqrt_U) * sqrt_U;
1008 return std::make_tuple(G_0, G_m1);
1022 static void eval_urr(Real* Gm_vec, Real T, Real U, Real zeta_over_two_rho,
size_t mmax) {
1026 const Real sqrt_U = sqrt(U);
1027 const Real sqrt_T = sqrt(T);
1028 const Real oo_sqrt_T = 1 / sqrt_T;
1029 const Real oo_sqrt_U = 1 / sqrt_U;
1030 const Real kappa = sqrt_U - sqrt_T;
1031 const Real lambda = sqrt_U + sqrt_T;
1032 const Real sqrtPi_over_4(0.44311346272637900682454187083528629569938736403060);
1033 const Real pfac = sqrtPi_over_4;
1034 const Real erfc_k = exp(kappa*kappa - T) * erfc(kappa);
1035 const Real erfc_l = exp(lambda*lambda - T) * erfc(lambda);
1040 Gmm1 = pfac * (erfc_k + erfc_l) * oo_sqrt_U;
1041 Gm = pfac * (erfc_k - erfc_l) * oo_sqrt_T;
1043#if __cplusplus >= 201703L
1050 Gm_vec[0] = (Gmm1 - Gm) * zeta_over_two_rho;
1056 const Real oo_two_T = 0.5 / T;
1057 const Real two_U = 2.0 * U;
1058 const Real exp_mT = exp(-T);
1060 for(
unsigned int m=0, two_m_minus_1=1; m<mmax; ++m, two_m_minus_1+=2) {
1061 Gmp1 = oo_two_T * (two_m_minus_1 * Gm + two_U * Gmm1 - exp_mT);
1063#if __cplusplus >= 201703L
1067 Gm_vec[m + 1] = Gmp1;
1069 Gm_vec[m + 1] = (Gm - Gmp1) * zeta_over_two_rho;
1087 void interpolate_Gm(Real* Gm_vec, Real T, Real U, Real zeta_over_two_rho,
long mmax)
const {
1089 assert(U >= Umin && U <= Umax);
1092 auto linear_map_02 = [](Real x) {
1093 assert(x >= 0 && x <= 2);
1094 return (x - 1) * 0.5;
1097 auto log2_map = [](Real x, Real one_over_a) {
1098 return std::log2(x * one_over_a) - 0.5;
1101 auto log10_map = [](Real x, Real one_over_a) {
1102 return std::log10(x * one_over_a) - 0.5;
1106 const int Tint = T < 2 ? 0 : int(std::floor(std::log2(T))); assert(Tint >= 0 && Tint < 10);
1108 constexpr Real one_over_2K[] = {1, 0.5, 0.25, 0.125, 0.0625, 0.03125, 0.015625, 0.0078125, 0.00390625, .001953125};
1110 const int Uint = int(std::floor(std::log10(U / Umin))); assert(Uint >= 0 && Uint < 10);
1112 constexpr Real one_over_10K[] = {1. / detail::pow10(cheb_table_uminlog10),
1113 1. / detail::pow10(cheb_table_uminlog10+1),
1114 1. / detail::pow10(cheb_table_uminlog10+2),
1115 1. / detail::pow10(cheb_table_uminlog10+3),
1116 1. / detail::pow10(cheb_table_uminlog10+4),
1117 1. / detail::pow10(cheb_table_uminlog10+5),
1118 1. / detail::pow10(cheb_table_uminlog10+6),
1119 1. / detail::pow10(cheb_table_uminlog10+7),
1120 1. / detail::pow10(cheb_table_uminlog10+8),
1121 1. / detail::pow10(cheb_table_uminlog10+9)};
1122 const Real t = Tint == 0 ? linear_map_02(T) : log2_map(T, one_over_2K[Tint]);
1123 const Real u = log10_map(U, one_over_10K[Uint]);
1125 const int interval = Tint * 10 + Uint;
1128 assert(ORDERp1 == 16);
1129 const auto t2 = t*t;
1130 const auto t3 = t2*t;
1131 const auto t4 = t2*t2;
1132 const auto t5 = t2*t3;
1133 const auto t6 = t3*t3;
1134 const auto t7 = t3*t4;
1135 const auto t8 = t4*t4;
1136 const auto t9 = t4*t5;
1137 const auto t10 = t5*t5;
1138 const auto t11 = t5*t6;
1139 const auto t12 = t6*t6;
1140 const auto t13 = t6*t7;
1141 const auto t14 = t7*t7;
1142 const auto t15 = t7*t8;
1143 const auto u2 = u*u;
1144 const auto u3 = u2*u;
1145 const auto u4 = u2*u2;
1146 const auto u5 = u2*u3;
1147 const auto u6 = u3*u3;
1148 const auto u7 = u3*u4;
1149 const auto u8 = u4*u4;
1150 const auto u9 = u4*u5;
1151 const auto u10 = u5*u5;
1152 const auto u11 = u5*u6;
1153 const auto u12 = u6*u6;
1154 const auto u13 = u6*u7;
1155 const auto u14 = u7*u7;
1156 const auto u15 = u7*u8;
1165 constexpr bool compute_Gmm10 =
true;
1167 if (compute_Gmm10) {
1170 std::tie(Exp ? G0 : Gm_vec[0], Gmm1) = eval_G0_and_maybe_Gm1<Exp>(T, U);
1172#if __cplusplus >= 201703L
1176 Gm_vec[0] = (Gmm1 - G0) * zeta_over_two_rho;
1182 mmin_interp = Exp ? -1 : 0;
1185 for(
long m=mmin_interp; m<=mmax; ++m){
1186 const Real *c_tuint = c_ + (ORDERp1) * (ORDERp1) * (interval * (mmax_ - mmin_ + 1) + (m - mmin_));
1189 c20v, c21v, c22v, c23v, c30v, c31v, c32v, c33v,
1190 c40v, c41v, c42v, c43v, c50v, c51v, c52v, c53v,
1191 c60v, c61v, c62v, c63v, c70v, c71v, c72v, c73v;
1193 ca0v, ca1v, ca2v, ca3v, cb0v, cb1v, cb2v, cb3v,
1194 cc0v, cc1v, cc2v, cc3v, cd0v, cd1v, cd2v, cd3v,
1195 ce0v, ce1v, ce2v, ce3v, cf0v, cf1v, cf2v, cf3v;
1276 for(
int i=1; i!=16; ++i) {
1277 uvec[i] = uvec[i-1] * u;
1278 tvec[i] = tvec[i-1] * t;
1281 for(
int i=0, ij=0; i!=16; ++i) {
1282 for (
int j = 0; j != 16; ++j, ++ij) {
1283 Gm += c_tuint[ij] * tvec[i] * uvec[j];
1289#if __cplusplus >= 201703L
1297 Gm_vec[m] = (Gmm1 - Gm) * zeta_over_two_rho;
1309 ExpensiveNumbers<Real> numbers_;
1316 int status = posix_memalign(&result, std::max(
sizeof(Real), 32ul), (mmax_ - mmin_ + 1) * cheb_table_nintervals * ORDERp1 * ORDERp1 *
sizeof(Real));
1318 if (status == EINVAL)
1319 throw std::logic_error(
1320 "TennoGmEval::init() : posix_memalign failed, alignment must be a power of 2 at least as large as sizeof(void *)");
1321 if (status == ENOMEM)
1322 throw std::bad_alloc();
1325 c_ =
static_cast<Real*
>(result);
1329 for (std::size_t iv = 0; iv < cheb_table_nintervals; ++iv) {
1331 std::copy(cheb_table[iv], cheb_table[iv]+((mmax_-mmin_)+1)*ORDERp1*ORDERp1, c_+(iv*((mmax_-mmin_)+1))*ORDERp1*ORDERp1);
1338#if LIBINT2_CONSTEXPR_STATICS
1339 template <
typename Real>
1341 double TennoGmEval<Real>::cheb_table[TennoGmEval<Real>::cheb_table_nintervals][(TennoGmEval<Real>::cheb_table_mmax+2)*(TennoGmEval<Real>::interpolation_order+1)*(TennoGmEval<Real>::interpolation_order+1)];
1345 template <
typename Real>
1346 double TennoGmEval<Real>::cheb_table[TennoGmEval<Real>::cheb_table_nintervals][(TennoGmEval<Real>::cheb_table_mmax+2)*(TennoGmEval<Real>::interpolation_order+1)*(TennoGmEval<Real>::interpolation_order+1)];
1350 template<
typename Real,
int k>
1362 template <
typename Real>
1364 std::vector<Real> Fm_;
1365 std::vector<Real> g_i;
1366 std::vector<Real> r_i;
1367 std::vector<Real> oorhog_i;
1374 void init(
int mmax) {
1378 oorhog_i.resize(mmax+1);
1410 template<
typename Real,
int k>
1413#ifndef LIBINT_USER_DEFINED_REAL
1423 detail::CoreEvalScratch<
GaussianGmEval<Real, k>>(mmax), mmax_(mmax),
1424 precision_(precision), fm_eval_(),
1425 numbers_(-1,-1,mmax) {
1426 assert(k == -1 || k == 0 || k == 2);
1429 fm_eval_ = FmEvalType::instance(mmax_, precision_);
1438 static std::shared_ptr<GaussianGmEval> instance(
unsigned int mmax, Real precision = std::numeric_limits<Real>::epsilon()) {
1440 assert(precision >= 0);
1442 static auto instance_ = std::make_shared<GaussianGmEval>(mmax, precision);
1444 while (instance_->max_m() < mmax || instance_->precision() > precision) {
1445 static std::mutex mtx;
1446 std::lock_guard<std::mutex> lck(mtx);
1447 if (instance_->max_m() < mmax || instance_->precision() > precision) {
1448 auto new_instance = std::make_shared<GaussianGmEval>(mmax, precision);
1449 instance_ = new_instance;
1457 int max_m()
const {
return mmax_; }
1459 Real precision()
const {
return precision_; }
1475 template <
typename AnyReal>
1476 void eval(Real* Gm, Real rho, Real T,
size_t mmax,
1477 const std::vector<std::pair<AnyReal, AnyReal> >& geminal,
1480 std::fill(Gm, Gm+mmax+1, Real(0));
1482 const auto sqrt_rho = sqrt(rho);
1483 const auto oo_sqrt_rho = 1/sqrt_rho;
1485 void* _scr = (scr == 0) ?
this : scr;
1486 auto& scratch = *(
reinterpret_cast<detail::CoreEvalScratch<GaussianGmEval<Real, -1
>>*>(_scr));
1487 for(
int i=1; i<=mmax; i++) {
1488 scratch.r_i[i] = scratch.r_i[i-1] * rho;
1492 typedef typename std::vector<std::pair<AnyReal, AnyReal> >::const_iterator citer;
1493 const citer gend = geminal.end();
1494 for(citer i=geminal.begin(); i!= gend; ++i) {
1496 const auto gamma = i->first;
1497 const auto gcoef = i->second;
1498 const auto rhog = rho + gamma;
1499 const auto oorhog = 1/rhog;
1501 const auto gorg = gamma * oorhog;
1502 const auto rorg = rho * oorhog;
1503 const auto sqrt_rho_org = sqrt_rho * oorhog;
1504 const auto sqrt_rhog = sqrt(rhog);
1505 const auto sqrt_rorg = sqrt_rho_org * sqrt_rhog;
1508 constexpr Real const_SQRTPI_2(0.88622692545275801364908374167057259139877472806119);
1509 const auto SS_K0G12_SS = gcoef * oo_sqrt_rho * const_SQRTPI_2 * rorg * sqrt_rorg * exp(-gorg*T);
1512 void* _scr = (scr == 0) ?
this : scr;
1513 auto& scratch = *(
reinterpret_cast<detail::CoreEvalScratch<GaussianGmEval<Real, -1
>>*>(_scr));
1515 const auto rorgT = rorg * T;
1516 fm_eval_->eval(&scratch.Fm_[0], rorgT, mmax);
1519 constexpr Real const_2_SQRTPI(1.12837916709551257389615890312154517);
1520 const auto pfac = const_2_SQRTPI * sqrt_rhog * SS_K0G12_SS;
1521 scratch.oorhog_i[0] = pfac;
1522 for(
int i=1; i<=mmax; i++) {
1523 scratch.g_i[i] = scratch.g_i[i-1] * gamma;
1524 scratch.oorhog_i[i] = scratch.oorhog_i[i-1] * oorhog;
1526 for(
int m=0; m<=mmax; m++) {
1528 Real* bcm = numbers_.bc[m];
1529 for(
int n=0; n<=m; n++) {
1530 ssss += bcm[n] * scratch.r_i[n] * scratch.g_i[m-n] * scratch.Fm_[n];
1532 Gm[m] += ssss * scratch.oorhog_i[m];
1538 auto ss_oper_ss_m = SS_K0G12_SS;
1539 Gm[0] += ss_oper_ss_m;
1540 for(
int m=1; m<=mmax; ++m) {
1541 ss_oper_ss_m *= gorg;
1542 Gm[m] += ss_oper_ss_m;
1549 const auto rorgT = rorg * T;
1550 const auto SS_K2G12_SS_0 = (1.5 + rorgT) * (SS_K0G12_SS * oorhog);
1551 const auto SS_K2G12_SS_m1 = rorg * (SS_K0G12_SS * oorhog);
1553 auto SS_K2G12_SS_gorg_m = SS_K2G12_SS_0 ;
1554 auto SS_K2G12_SS_gorg_m1 = SS_K2G12_SS_m1;
1555 Gm[0] += SS_K2G12_SS_gorg_m;
1556 for(
int m=1; m<=mmax; ++m) {
1557 SS_K2G12_SS_gorg_m *= gorg;
1558 Gm[m] += SS_K2G12_SS_gorg_m - m * SS_K2G12_SS_gorg_m1;
1559 SS_K2G12_SS_gorg_m1 *= gorg;
1570 std::shared_ptr<const FmEvalType> fm_eval_;
1572 ExpensiveNumbers<Real> numbers_;
1575 template <
typename GmEvalFunction>
1576 struct GenericGmEval :
private GmEvalFunction {
1578 typedef typename GmEvalFunction::value_type Real;
1580 GenericGmEval(
int mmax, Real precision) : GmEvalFunction(mmax, precision),
1581 mmax_(mmax), precision_(precision) {}
1583 static std::shared_ptr<const GenericGmEval> instance(
int mmax, Real precision = std::numeric_limits<Real>::epsilon()) {
1584 return std::make_shared<const GenericGmEval>(mmax, precision);
1587 template <
typename Real,
typename... ExtraArgs>
1588 void eval(Real* Gm, Real rho, Real T,
int mmax, ExtraArgs... args)
const {
1589 assert(mmax <= mmax_);
1590 (GmEvalFunction(*
this))(Gm, rho, T, mmax, std::forward<ExtraArgs>(args)...);
1594 int max_m()
const {
return mmax_; }
1596 Real precision()
const {
return precision_; }
1604 namespace os_core_ints {
1605 template <
typename Real,
int K>
struct r12_xx_K_gm_eval;
1606 template <
typename Real>
struct erfc_coulomb_gm_eval;
1611 template <
typename Real>
1612 struct CoreEvalScratch<os_core_ints::r12_xx_K_gm_eval<Real, 1>> {
1613 std::vector<Real> Fm_;
1614 CoreEvalScratch(
const CoreEvalScratch&) =
default;
1615 CoreEvalScratch(CoreEvalScratch&&) =
default;
1617 explicit CoreEvalScratch(
int mmax) { Fm_.resize(mmax+2); }
1620 template <
typename Real>
1621 struct CoreEvalScratch<os_core_ints::erfc_coulomb_gm_eval<Real>> {
1622 std::vector<Real> Fm_;
1623 CoreEvalScratch(
const CoreEvalScratch&) =
default;
1624 CoreEvalScratch(CoreEvalScratch&&) =
default;
1626 explicit CoreEvalScratch(
int mmax) { Fm_.resize(mmax+1); }
1631 namespace os_core_ints {
1634 template <
typename Real>
1635 struct delta_gm_eval {
1636 typedef Real value_type;
1638 delta_gm_eval(
unsigned int, Real) {}
1639 void operator()(Real* Gm, Real rho, Real T,
int mmax)
const {
1640 constexpr static auto one_over_two_pi = 1.0 / (2.0 * M_PI);
1641 const auto G0 = exp(-T) * rho * one_over_two_pi;
1642 std::fill(Gm, Gm + mmax + 1, G0);
1651 template <
typename Real,
int K>
1652 struct r12_xx_K_gm_eval;
1654 template <
typename Real>
1655 struct r12_xx_K_gm_eval<Real, 1>
1656 :
private detail::CoreEvalScratch<r12_xx_K_gm_eval<Real, 1>> {
1657 typedef detail::CoreEvalScratch<r12_xx_K_gm_eval<Real, 1>> base_type;
1658 typedef Real value_type;
1660#ifndef LIBINT_USER_DEFINED_REAL
1666 r12_xx_K_gm_eval(
unsigned int mmax, Real precision)
1668 fm_eval_ = FmEvalType::instance(mmax + 1, precision);
1670 void operator()(Real* Gm, Real rho, Real T,
int mmax) {
1671 fm_eval_->eval(&base_type::Fm_[0], T, mmax + 1);
1672 auto T_plus_m_plus_one = T + 1.0;
1673 Gm[0] = T_plus_m_plus_one * base_type::Fm_[0] - T * base_type::Fm_[1];
1674 auto minus_m = -1.0;
1675 T_plus_m_plus_one += 1.0;
1676 for (
auto m = 1; m <= mmax;
1677 ++m, minus_m -= 1.0, T_plus_m_plus_one += 1.0) {
1679 minus_m * base_type::Fm_[m - 1] + T_plus_m_plus_one * base_type::Fm_[m] - T * base_type::Fm_[m + 1];
1684 std::shared_ptr<const FmEvalType> fm_eval_;
1688 template <
typename Real>
1689 struct erf_coulomb_gm_eval {
1690 typedef Real value_type;
1692#ifndef LIBINT_USER_DEFINED_REAL
1698 erf_coulomb_gm_eval(
unsigned int mmax, Real precision) {
1699 fm_eval_ = FmEvalType::instance(mmax, precision);
1701 void operator()(Real* Gm, Real rho, Real T,
int mmax, Real omega)
const {
1703 auto omega2 = omega * omega;
1704 auto omega2_over_omega2_plus_rho = omega2 / (omega2 + rho);
1705 fm_eval_->eval(Gm, T * omega2_over_omega2_plus_rho,
1709 auto ooversqrto2prho_exp_2mplus1 =
1710 sqrt(omega2_over_omega2_plus_rho);
1711 for (
auto m = 0; m <= mmax;
1712 ++m, ooversqrto2prho_exp_2mplus1 *= omega2_over_omega2_plus_rho) {
1713 Gm[m] *= ooversqrto2prho_exp_2mplus1;
1717 std::fill(Gm, Gm+mmax+1, Real{0});
1722 std::shared_ptr<const FmEvalType> fm_eval_;
1728 template <
typename Real>
1729 struct erfc_coulomb_gm_eval :
private
1730 detail::CoreEvalScratch<erfc_coulomb_gm_eval<Real>> {
1731 typedef detail::CoreEvalScratch<erfc_coulomb_gm_eval<Real>> base_type;
1732 typedef Real value_type;
1734 #ifndef LIBINT_USER_DEFINED_REAL
1740 erfc_coulomb_gm_eval(
unsigned int mmax, Real precision)
1742 fm_eval_ = FmEvalType::instance(mmax, precision);
1744 void operator()(Real* Gm, Real rho, Real T,
int mmax, Real omega) {
1745 fm_eval_->eval(&base_type::Fm_[0], T, mmax);
1746 std::copy(base_type::Fm_.cbegin(), base_type::Fm_.cbegin() + mmax + 1, Gm);
1748 auto omega2 = omega * omega;
1749 auto omega2_over_omega2_plus_rho = omega2 / (omega2 + rho);
1750 fm_eval_->eval(&base_type::Fm_[0], T * omega2_over_omega2_plus_rho,
1754 auto ooversqrto2prho_exp_2mplus1 =
1755 sqrt(omega2_over_omega2_plus_rho);
1756 for (
auto m = 0; m <= mmax;
1757 ++m, ooversqrto2prho_exp_2mplus1 *= omega2_over_omega2_plus_rho) {
1758 Gm[m] -= ooversqrto2prho_exp_2mplus1 * base_type::Fm_[m];
1764 std::shared_ptr<const FmEvalType> fm_eval_;
1778 template <
typename Real>
1782 return -std::exp(-zeta*x)/zeta;
1785 template <
typename Real>
1787 fngtg(
const std::vector<Real>& cc,
1788 const std::vector<Real>& aa,
1791 const Real x2 = x * x;
1792 const unsigned int n = cc.size();
1793 for(
unsigned int i=0; i<n; ++i)
1794 value += cc[i] * std::exp(- aa[i] * x2);
1801 template <
typename Real>
1803 wwtewklopper(Real x) {
1804 const Real x2 = x * x;
1805 return x2 * std::exp(-2 * x2);
1807 template <
typename Real>
1810 const Real x2 = x * x;
1811 const Real x6 = x2 * x2 * x2;
1812 return std::exp(-0.005 * x6);
1815 template <
typename Real>
1822 template <
typename Real>
1824 norm(
const std::vector<Real>& vec) {
1826 const unsigned int n = vec.size();
1827 for(
unsigned int i=0; i<n; ++i)
1828 value += vec[i] * vec[i];
1832 template <
typename Real>
1833 void LinearSolveDamped(
const std::vector<Real>& A,
1834 const std::vector<Real>& b,
1836 std::vector<Real>& x) {
1837 const size_t n = b.size();
1838 std::vector<Real> Acopy(A);
1839 for(
size_t m=0; m<n; ++m) Acopy[m*n + m] *= (1 + lambda);
1840 std::vector<Real> e(b);
1844 std::vector<int> ipiv(n);
1848 dgesv_(&n, &one, &Acopy[0], &n, &ipiv[0], &e[0], &n, &info);
1865 template <
typename Real>
1866 void stg_ng_fit(
unsigned int n,
1868 std::vector< std::pair<Real, Real> >& geminal,
1871 unsigned int npts = 1001) {
1874 std::vector<Real> cc(n, 1.0);
1875 std::vector<Real> aa(n);
1876 for(
unsigned int i=0; i<n; ++i)
1877 aa[i] = std::pow(3.0, (i + 2 - (n + 1)/2.0));
1880 Real ffnormfac = 0.0;
1882 for(
unsigned int i=0; i<n; ++i)
1883 for(
unsigned int j=0; j<n; ++j)
1884 ffnormfac += cc[i] * cc[j]/sqrt(aa[i] + aa[j]);
1885 const Real Nf = sqrt(2.0 * zeta) * zeta;
1886 const Real Nff = sqrt(2.0) / (sqrt(ffnormfac) *
1888 for(
unsigned int i=0; i<n; ++i) cc[i] *= -Nff/Nf;
1890 Real lambda0 = 1000;
1891 const Real nu = 3.0;
1892 const Real epsilon = 1e-15;
1893 const unsigned int maxniter = 200;
1896 std::vector<Real> xi(npts);
1897 for(
unsigned int i=0; i<npts; ++i) xi[i] = xmin + (xmax - xmin)*i/(npts - 1);
1899 std::vector<Real> err(npts);
1901 const size_t nparams = 2*n;
1902 std::vector<Real> J( npts * nparams );
1903 std::vector<Real> delta(nparams);
1910 Real errnormIm1 = 1e3;
1911 bool converged =
false;
1912 unsigned int iter = 0;
1913 while (!converged && iter < maxniter) {
1916 for(
unsigned int i=0; i<npts; ++i) {
1917 const Real x = xi[i];
1918 err[i] = (fstg(zeta, x) - fngtg(cc, aa, x)) * sqrt(ww(x));
1920 errnormI = norm(err)/sqrt((Real)npts);
1923 converged = std::abs((errnormI - errnormIm1)/errnormIm1) <= epsilon;
1924 if (converged)
break;
1925 errnormIm1 = errnormI;
1927 for(
unsigned int i=0; i<npts; ++i) {
1928 const Real x2 = xi[i] * xi[i];
1929 const Real sqrt_ww_x = sqrt(ww(xi[i]));
1930 const unsigned int ioffset = i * nparams;
1931 for(
unsigned int j=0; j<n; ++j)
1932 J[ioffset+j] = (std::exp(-aa[j] * x2)) * sqrt_ww_x;
1933 const unsigned int ioffsetn = ioffset+n;
1934 for(
unsigned int j=0; j<n; ++j)
1935 J[ioffsetn+j] = - sqrt_ww_x * x2 * cc[j] * std::exp(-aa[j] * x2);
1938 std::vector<Real> A( nparams * nparams);
1939 for(
size_t r=0, rc=0; r<nparams; ++r) {
1940 for(
size_t c=0; c<nparams; ++c, ++rc) {
1942 for(
size_t i=0, ir=r, ic=c; i<npts; ++i, ir+=nparams, ic+=nparams)
1943 Arc += J[ir] * J[ic];
1948 std::vector<Real> b( nparams );
1949 for(
size_t r=0; r<nparams; ++r) {
1951 for(
size_t i=0, ir=r; i<npts; ++i, ir+=nparams)
1952 br += J[ir] * err[i];
1959 for(
int l=-1; l<1000; ++l) {
1961 LinearSolveDamped(A, b, lambda0, delta );
1963 std::vector<double> cc_0(cc);
for(
unsigned int i=0; i<n; ++i) cc_0[i] += delta[i];
1964 std::vector<double> aa_0(aa);
for(
unsigned int i=0; i<n; ++i) aa_0[i] += delta[i+n];
1967 bool step_too_large =
false;
1968 for(
unsigned int i=0; i<n; ++i)
1969 if (aa_0[i] < 0.0) {
1970 step_too_large =
true;
1973 if (!step_too_large) {
1974 std::vector<double> err_0(npts);
1975 for(
unsigned int i=0; i<npts; ++i) {
1976 const double x = xi[i];
1977 err_0[i] = (fstg(zeta, x) - fngtg(cc_0, aa_0, x)) * sqrt(ww(x));
1979 const double errnorm_0 = norm(err_0)/sqrt((
double)npts);
1980 if (errnorm_0 < errnormI) {
1995 assert(not (iter == maxniter && errnormI > 1e-10));
1997 for(
unsigned int i=0; i<n; ++i)
1998 geminal[i] = std::make_pair(aa[i], cc[i]);
holds tables of expensive quantities
Definition: boys.h:60
Computes the Boys function, $ F_m (T) = \int_0^1 u^{2m} \exp(-T u^2) \, {\rm d}u $,...
Definition: boys.h:245
static std::shared_ptr< const FmEval_Chebyshev7 > instance(int m_max, double=0.0)
Singleton interface allows to manage the lone instance; adjusts max m values as needed in thread-safe...
Definition: boys.h:298
void eval(Real *Fm, Real x, int m_max) const
fills in Fm with computed Boys function values for m in [0,mmax]
Definition: boys.h:323
FmEval_Chebyshev7(int m_max, double precision=std::numeric_limits< double >::epsilon())
Definition: boys.h:267
int max_m() const
Definition: boys.h:317
Computes the Boys function, $ F_m (T) = \int_0^1 u^{2m} \exp(-T u^2) \, {\rm d}u $,...
Definition: boys.h:479
static std::shared_ptr< const FmEval_Taylor > instance(unsigned int mmax, Real precision=std::numeric_limits< Real >::epsilon())
Singleton interface allows to manage the lone instance; adjusts max m and precision values as needed ...
Definition: boys.h:595
void eval(Real *Fm, Real T, int mmax) const
computes Boys function values with m index in range [0,mmax]
Definition: boys.h:623
int max_m() const
Definition: boys.h:614
Real precision() const
Definition: boys.h:616
FmEval_Taylor(unsigned int mmax, Real precision=std::numeric_limits< Real >::epsilon())
Constructs the object to be able to compute Boys funcion for m in [0,mmax], with relative precision.
Definition: boys.h:488
double horizontal_add(VectorSSEDouble const &a)
Horizontal add.
Definition: vector_x86.h:232
Defaults definitions for various parameters assumed by Libint.
Definition: algebra.cc:24
std::ostream & verbose_stream()
Accessor for the disgnostics stream.
Definition: initialize.h:100
bool verbose()
Accessor for the verbose flag.
Definition: initialize.h:106
Computes the Boys function, $ F_m (T) = \int_0^1 u^{2m} \exp(-T u^2) \, {\rm d}u $,...
Definition: boys.h:205
static void eval(Real *Fm, Real t, size_t mmax)
fills up an array of Fm(T) for m in [0,mmax]
Definition: boys.h:219
Computes the Boys function, , using single algorithm (asymptotic expansion).
Definition: boys.h:142
static void eval(Real *Fm, Real T, size_t mmax)
fills up an array of Fm(T) for m in [0,mmax]
Definition: boys.h:182
static Real eval(Real T, size_t m)
computes a single value of using MacLaurin series to full precision of Real
Definition: boys.h:153
core integral for Yukawa and exponential interactions
Definition: boys.h:832
void eval_slater(Real *Gm, Real one_over_rho, Real T, size_t mmax, Real zeta) const
Definition: boys.h:942
static std::shared_ptr< const TennoGmEval > instance(int m_max, double=0)
Singleton interface allows to manage the lone instance; adjusts max m values as needed in thread-safe...
Definition: boys.h:888
Real precision() const
Definition: boys.h:908
void eval_yukawa(Real *Gm, Real one_over_rho, Real T, size_t mmax, Real zeta) const
Definition: boys.h:920
TennoGmEval(unsigned int mmax, Real precision=-1)
Definition: boys.h:852
some evaluators need thread-local scratch, but most don't
Definition: boys.h:1356
SIMD vector of 4 double-precision floating-point real numbers, operations on which use AVX instructio...
Definition: vector_x86.h:639
void convert(T *a) const
writes this to a
Definition: vector_x86.h:729
void load(T const *a)
loads a to this
Definition: vector_x86.h:720
void load_aligned(T const *a)
loads a to this
Definition: vector_x86.h:725