21#ifndef _libint2_src_lib_libint_shell_h_
22#define _libint2_src_lib_libint_shell_h_
24#include <libint2/util/cxxstd.h>
25#if LIBINT2_CPLUSPLUS_STD < 2011
26# error "libint2/shell.h requires C++11 support"
37#include <libint2/util/small_vector.h>
43 static constexpr std::array<int64_t,21> fac = {{1LL, 1LL, 2LL, 6LL, 24LL, 120LL, 720LL, 5040LL, 40320LL, 362880LL, 3628800LL, 39916800LL,
44 479001600LL, 6227020800LL, 87178291200LL, 1307674368000LL, 20922789888000LL,
45 355687428096000LL, 6402373705728000LL, 121645100408832000LL,
46 2432902008176640000LL}};
48 static constexpr std::array<int64_t,31> df_Kminus1 = {{1LL, 1LL, 1LL, 2LL, 3LL, 8LL, 15LL, 48LL, 105LL, 384LL, 945LL, 3840LL, 10395LL, 46080LL, 135135LL,
49 645120LL, 2027025LL, 10321920LL, 34459425LL, 185794560LL, 654729075LL,
50 3715891200LL, 13749310575LL, 81749606400LL, 316234143225LL, 1961990553600LL,
51 7905853580625LL, 51011754393600LL, 213458046676875LL, 1428329123020800LL,
54 template <
typename Int> int64_t bc(Int i, Int j) {
55 assert(i < Int(fac.size()));
56 assert(j < Int(fac.size()));
58 return fac[i] / (fac[j] * fac[i-j]);
82 typedef double real_t;
88 svector<real_t> coeff;
91 return &other ==
this || (l == other.l && pure == other.pure && coeff == other.coeff);
94 return not this->operator==(other);
96 size_t cartesian_size()
const {
97 return (l + 1) * (l + 2) / 2;
100 return pure ? (2 * l + 1) : cartesian_size();
113 alpha(std::move(other.alpha)),
114 contr(std::move(other.contr)),
115 O(std::move(other.O)),
121 alpha = std::move(other.alpha);
122 contr = std::move(other.contr);
123 O = std::move(other.O);
129 svector<Contraction> _contr,
131 bool embed_normalization_into_coefficients =
true) :
132 alpha(std::move(_alpha)),
133 contr(std::move(_contr)),
136 if (embed_normalization_into_coefficients)
139 update_max_ln_coeff();
144 O = std::move(new_origin);
148 size_t cartesian_size()
const {
150 for(
const auto& c:
contr) { s += c.cartesian_size(); }
153 size_t size()
const {
155 for(
const auto& c:
contr) { s += c.size(); }
159 size_t ncontr()
const {
return contr.size(); }
160 size_t nprim()
const {
return alpha.size(); }
162 bool operator==(
const Shell& other)
const {
163 return &other ==
this || (
O == other.O &&
alpha == other.alpha &&
contr == other.contr);
165 bool operator!=(
const Shell& other)
const {
166 return not this->operator==(other);
169 static char am_symbol(
size_t l) {
170 static char lsymb[] =
"spdfghikmnoqrtuvwxyz";
174 static unsigned short am_symbol_to_l(
char am_symbol) {
175 const char AM_SYMBOL = ::toupper(am_symbol);
197 default:
throw "invalid angular momentum label";
202 typedef enum {false_value=0,true_value=1,default_value=2} value_t;
205 bool is_default()
const {
return value_ == default_value; }
206 operator bool()
const { assert(value_ != default_value);
return value_ == true_value; }
216 static bool result{
true};
217 if (not flag.is_default()) {
225 static const Shell unitshell{make_unit()};
232 const auto alpha = this->alpha.at(p);
233 assert(
alpha >= 0.0);
234 const auto l =
contr.at(c).l;
237 using libint2::math::df_Kminus1;
238 const auto sqrt_Pi_cubed = real_t{5.56832799683170784528481798212};
239 const auto two_alpha = 2 *
alpha;
240 const auto two_alpha_to_am32 = pow(two_alpha,l+1) * sqrt(two_alpha);
241 const auto one_over_N = sqrt((sqrt_Pi_cubed * df_Kminus1[2*l] )/(pow(2,l) * two_alpha_to_am32));
242 return contr.at(c).coeff[p] * one_over_N;
252 svector<Contraction> prim_contr;
253 prim_contr.reserve(ncontr());
254 for(
auto&& c:
contr) {
255 prim_contr.emplace_back(
Contraction{c.l, c.pure, {1.}});
269 contr{{0,
false, {1}}},
278 using libint2::math::df_Kminus1;
280 const auto sqrt_Pi_cubed = real_t{5.56832799683170784528481798212};
281 const auto np = nprim();
282 for(
auto& c: contr) {
284 for(
auto p=0ul; p!=np; ++p) {
285 assert(alpha[p] >= 0);
287 const auto two_alpha = 2 * alpha[p];
288 const auto two_alpha_to_am32 = pow(two_alpha,c.l+1) * sqrt(two_alpha);
289 const auto normalization_factor = sqrt(pow(2,c.l) * two_alpha_to_am32/(sqrt_Pi_cubed * df_Kminus1[2*c.l] ));
291 c.coeff[p] *= normalization_factor;
296 if (do_enforce_unit_normalization()) {
299 for(
auto p=0ul; p!=np; ++p) {
300 for(
decltype(p) q=0ul; q<=p; ++q) {
301 auto gamma = alpha[p] + alpha[q];
302 norm += (p==q ? 1 : 2) * df_Kminus1[2*c.l] * sqrt_Pi_cubed * c.coeff[p] * c.coeff[q] /
303 (pow(2,c.l) * pow(gamma,c.l+1) * sqrt(gamma));
306 auto normalization_factor = 1 / sqrt(norm);
307 for(
auto p=0ul; p!=np; ++p) {
308 c.coeff[p] *= normalization_factor;
314 update_max_ln_coeff();
317 void update_max_ln_coeff() {
319 max_ln_coeff.resize(nprim());
320 for(
auto p=0ul; p!=nprim(); ++p) {
321 real_t max_ln_c = - std::numeric_limits<real_t>::max();
322 for(
auto& c: contr) {
323 max_ln_c = std::max(max_ln_c, std::log(std::abs(c.coeff[p])));
325 max_ln_coeff[p] = max_ln_c;
331 inline std::ostream& operator<<(std::ostream& os,
const Shell& sh) {
332 os <<
"Shell:( O={" << sh.O[0] <<
"," << sh.O[1] <<
"," << sh.O[2] <<
"}" << std::endl;
334 for(
const auto& c: sh.contr) {
335 os <<
" {l=" << c.l <<
",sph=" << c.pure <<
"}";
339 for(
auto i=0ul; i<sh.alpha.size(); ++i) {
340 os <<
" " << sh.alpha[i];
341 for(
const auto& c: sh.contr) {
342 os <<
" " << c.coeff.at(i);
379 inline ScreeningMethod& default_screening_method_accessor() {
380 static ScreeningMethod default_screening_method = ScreeningMethod::Original;
381 return default_screening_method;
386 return detail::default_screening_method_accessor();
389 inline void default_screening_method(ScreeningMethod screening_method) {
390 detail::default_screening_method_accessor() = screening_method;
395 typedef Shell::real_t real_t;
410 std::vector<PrimPairData> primpairs;
412 real_t ln_prec = std::numeric_limits<real_t>::lowest();
415 ShellPair() : primpairs() {
for(
int i=0; i!=3; ++i) AB[i] = 0.; }
417 ShellPair(
size_t max_nprim) : primpairs() {
418 primpairs.reserve(max_nprim*max_nprim);
419 for(
int i=0; i!=3; ++i) AB[i] = 0.;
421 template <
typename Real> ShellPair(
const Shell& s1,
const Shell& s2, Real ln_prec, ScreeningMethod screening_method = default_screening_method()) {
422 init(s1, s2, ln_prec, screening_method);
424 template <
typename Real,
425 typename SchwarzFactorEvaluator>
426 ShellPair(
const Shell& s1,
const Shell& s2, Real ln_prec, ScreeningMethod screening_method,
427 SchwarzFactorEvaluator&& schwarz_factor_evaluator) {
428 init(s1, s2, ln_prec, screening_method,
429 std::forward<SchwarzFactorEvaluator>(schwarz_factor_evaluator));
435 for(
int i=0; i!=3; ++i) AB[i] = 0.;
436 ln_prec = std::numeric_limits<real_t>::lowest();
437 screening_method_ = ScreeningMethod::Invalid;
440 void resize(std::size_t max_nprim) {
441 const auto max_nprim2 = max_nprim * max_nprim;
442 if (max_nprim * max_nprim > primpairs.size())
443 primpairs.resize(max_nprim2);
447 template <
typename Real>
void init(
const Shell& s1,
const Shell& s2, Real ln_prec,
449 assert(screening_method == ScreeningMethod::Original || screening_method == ScreeningMethod::Conservative);
455 const auto& A = s1.
O;
456 const auto& B = s2.
O;
458 for(
int i=0; i!=3; ++i) {
463 auto max_l = [](
const Shell& s) {
468 const auto max_l1 = max_l(s1);
469 const auto max_l2 = max_l(s2);
471 const auto nprim1 = s1.
alpha.size();
472 const auto nprim2 = s2.
alpha.size();
474 for(
size_t p1=0; p1!=nprim1; ++p1) {
475 for(
size_t p2=0; p2!=nprim2; ++p2) {
477 const auto& a1 = s1.
alpha[p1];
478 const auto& a2 = s2.
alpha[p2];
479 const auto gamma = a1 + a2;
480 const auto oogamma = 1 / gamma;
482 const auto rho = a1 * a2 * oogamma;
483 const auto minus_rho_times_AB2 = -rho*AB2;
485 if (screening_method == ScreeningMethod::Original && ln_screen_fac < ln_prec)
494 P[0] = (a1 * A[0] + a2 * B[0]) * oogamma;
495 P[1] = (a1 * A[1] + a2 * B[1]) * oogamma;
496 P[2] = (a1 * A[2] + a2 * B[2]) * oogamma;
506 real_t nonspherical_scr_factor = 0;
507 if (screening_method == ScreeningMethod::Conservative) {
508 const auto maxabs_PA_i_to_l1 =
509 std::pow(std::max(std::max(std::abs(P[0] - A[0]),
510 std::abs(P[1] - A[1])),
511 std::abs(P[2] - A[2])),
513 const auto maxabs_PB_i_to_l2 =
514 std::pow(std::max(std::max(std::abs(P[0] - B[0]),
515 std::abs(P[1] - B[1])),
516 std::abs(P[2] - B[2])),
518 const auto fac_l1_fac_l2_oogamma_to_l =
519 math::fac[max_l1] * math::fac[max_l2] *
520 std::pow(oogamma, max_l1 + max_l2);
521 nonspherical_scr_factor =
522 std::max(maxabs_PA_i_to_l1 * maxabs_PB_i_to_l2,
523 fac_l1_fac_l2_oogamma_to_l);
524 const auto ln_nonspherical_scr_factor =
525 log(std::max(nonspherical_scr_factor,
static_cast<real_t
>(1)));
527 constexpr decltype(rho) ln_sqrt_two_times_M_PI_to_1pt25 =
528 1.777485947591722872387900;
529 const auto ln_spherical_scr_extra_factor =
530 ln_sqrt_two_times_M_PI_to_1pt25 +
532 const auto ln_nprim = log(nprim1*nprim2);
533 ln_screen_fac += ln_spherical_scr_extra_factor +
534 ln_nonspherical_scr_factor + ln_nprim;
535 if (ln_screen_fac < ln_prec)
539 primpairs.resize(c+1);
544 constexpr decltype(rho) sqrt_two_times_M_PI_to_1pt25 =
545 5.9149671727956128778;
546 p.
K = sqrt_two_times_M_PI_to_1pt25 * exp(minus_rho_times_AB2) * oogamma;
557 this->ln_prec = ln_prec;
558 this->screening_method_ = screening_method;
562 template <
typename Real,
typename SchwarzFactorEvaluator>
void init(
const Shell& s1,
const Shell& s2, Real ln_prec,
564 SchwarzFactorEvaluator&& schwarz_factor_evaluator) {
565 assert(screening_method == ScreeningMethod::Schwarz || screening_method == ScreeningMethod::SchwarzInf);
571 const auto& A = s1.
O;
572 const auto& B = s2.
O;
574 for(
int i=0; i!=3; ++i) {
579 const auto nprim1 = s1.
alpha.size();
580 const auto nprim2 = s2.
alpha.size();
581 const auto nprim12 = nprim1 * nprim2;
583 for(
size_t p1=0; p1!=nprim1; ++p1) {
584 for(
size_t p2=0; p2!=nprim2; ++p2) {
586 const auto ln_screen_fac = log(nprim12 * schwarz_factor_evaluator(s1, p1, s2, p2)) + s1.
max_ln_coeff[p1] + s2.
max_ln_coeff[p2];
587 if (ln_screen_fac < ln_prec)
590 const auto& a1 = s1.
alpha[p1];
591 const auto& a2 = s2.
alpha[p2];
592 const auto gamma = a1 + a2;
593 const auto oogamma = 1 / gamma;
595 const auto rho = a1 * a2 * oogamma;
596 const auto minus_rho_times_AB2 = -rho*AB2;
604 P[0] = (a1 * A[0] + a2 * B[0]) * oogamma;
605 P[1] = (a1 * A[1] + a2 * B[1]) * oogamma;
606 P[2] = (a1 * A[2] + a2 * B[2]) * oogamma;
609 primpairs.resize(c+1);
614 constexpr decltype(rho) sqrt_two_times_M_PI_to_1pt25 =
615 5.9149671727956128778;
616 p.
K = sqrt_two_times_M_PI_to_1pt25 * exp(minus_rho_times_AB2) * oogamma;
627 this->ln_prec = ln_prec;
628 this->screening_method_ = screening_method;
Array idential to C++0X arrays.
Definition: stdarray_bits.h:14
Defaults definitions for various parameters assumed by Libint.
Definition: algebra.cc:24
ScreeningMethod
describes method for primitive screening used by ShellPair and Engine
Definition: shell.h:357
@ Original
standard screening method:
@ Conservative
conservative screening:
@ Schwarz
Schwarz screening method using Frobenius norm:
@ SchwarzInf
Schwarz screening method using infinity norm:
PrimPairData contains pre-computed primitive pair data.
Definition: shell.h:399
real_t ln_scr
natural log of the primitive pair screening factor (see ScreeningMethod )
Definition: shell.h:404
int p1
first primitive index
Definition: shell.h:405
real_t nonsph_screen_fac
used only when screening_method_==ScreeningMethod::Conservative: approximate upper bound for the modu...
Definition: shell.h:403
real_t P[3]
Definition: shell.h:400
real_t K
Definition: shell.h:401
int p2
second primitive index
Definition: shell.h:406
real_t one_over_gamma
Definition: shell.h:402
ShellPair contains pre-computed shell-pair data, primitive pairs are screened to finite precision.
Definition: shell.h:394
void init(const Shell &s1, const Shell &s2, Real ln_prec, ScreeningMethod screening_method=ScreeningMethod::Original)
initializes the shell pair data using original or conservative screening methods
Definition: shell.h:447
void reset()
makes this equivalent to a default-initialized ShellPair, however the memory allocated in primpairs i...
Definition: shell.h:433
void init(const Shell &s1, const Shell &s2, Real ln_prec, ScreeningMethod screening_method, SchwarzFactorEvaluator &&schwarz_factor_evaluator)
initializes the shell pair data using Schwarz screening methods
Definition: shell.h:562
contracted Gaussian = angular momentum + sph/cart flag + contraction coefficients
Definition: shell.h:85
generally-contracted Solid-Harmonic/Cartesion Gaussian Shell
Definition: shell.h:81
svector< Contraction > contr
contractions
Definition: shell.h:105
svector< real_t > max_ln_coeff
maximum ln of (absolute) contraction coefficient for each primitive
Definition: shell.h:107
Shell(svector< real_t > _alpha, svector< Contraction > _contr, std::array< real_t, 3 > _O, bool embed_normalization_into_coefficients=true)
Definition: shell.h:128
static bool do_enforce_unit_normalization(defaultable_boolean flag=defaultable_boolean())
sets and/or reports whether the auto-renormalization to unity is set if called without arguments,...
Definition: shell.h:215
static const Shell & unit()
Definition: shell.h:224
real_t coeff_normalized(size_t c, size_t p) const
Definition: shell.h:231
std::array< real_t, 3 > O
origin
Definition: shell.h:106
Shell extract_primitive(size_t p, bool unit_normalized=true) const
extract primitive shell
Definition: shell.h:250
svector< real_t > alpha
exponents
Definition: shell.h:104