LIBINT 2.7.2
shell.h
1/*
2 * Copyright (C) 2004-2021 Edward F. Valeev
3 *
4 * This file is part of Libint.
5 *
6 * Libint is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Libint is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with Libint. If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#ifndef _libint2_src_lib_libint_shell_h_
22#define _libint2_src_lib_libint_shell_h_
23
24#include <libint2/util/cxxstd.h>
25#if LIBINT2_CPLUSPLUS_STD < 2011
26# error "libint2/shell.h requires C++11 support"
27#endif
28
29#include <iostream>
30#include <array>
31#include <vector>
32#include <cassert>
33#include <cmath>
34
35#include <libint2.h>
36
37#include <libint2/util/small_vector.h>
38
39namespace libint2 {
40
41 namespace math {
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,
52 6190283353629375LL}};
54 template <typename Int> int64_t bc(Int i, Int j) {
55 assert(i < Int(fac.size()));
56 assert(j < Int(fac.size()));
57 assert(i >= j);
58 return fac[i] / (fac[j] * fac[i-j]);
59 }
60 }
61
63
81 struct Shell {
82 typedef double real_t;
83
85 struct Contraction {
86 int l;
87 bool pure;
88 svector<real_t> coeff;
89
90 bool operator==(const Contraction& other) const {
91 return &other == this || (l == other.l && pure == other.pure && coeff == other.coeff);
92 }
93 bool operator!=(const Contraction& other) const {
94 return not this->operator==(other);
95 }
96 size_t cartesian_size() const {
97 return (l + 1) * (l + 2) / 2;
98 }
99 size_t size() const {
100 return pure ? (2 * l + 1) : cartesian_size();
101 }
102 };
103
104 svector<real_t> alpha;
105 svector<Contraction> contr;
107 svector<real_t> max_ln_coeff;
108
109 Shell() = default;
110 Shell(const Shell&) = default;
111 // intel does not support "move ctor = default"
112 Shell(Shell&& other) noexcept :
113 alpha(std::move(other.alpha)),
114 contr(std::move(other.contr)),
115 O(std::move(other.O)),
116 max_ln_coeff(std::move(other.max_ln_coeff)) {
117 }
118 Shell& operator=(const Shell&) = default;
119 // intel does not support "move asgnmt = default"
120 Shell& operator=(Shell&& other) noexcept {
121 alpha = std::move(other.alpha);
122 contr = std::move(other.contr);
123 O = std::move(other.O);
124 max_ln_coeff = std::move(other.max_ln_coeff);
125 return *this;
126 }
128 Shell(svector<real_t> _alpha,
129 svector<Contraction> _contr,
131 bool embed_normalization_into_coefficients = true) :
132 alpha(std::move(_alpha)),
133 contr(std::move(_contr)),
134 O(std::move(_O)) {
135 // embed normalization factors into contraction coefficients
136 if (embed_normalization_into_coefficients)
137 renorm();
138 else {
139 update_max_ln_coeff();
140 }
141 }
142
143 Shell& move(std::array<real_t, 3> new_origin) {
144 O = std::move(new_origin);
145 return *this;
146 }
147
148 size_t cartesian_size() const {
149 size_t s = 0;
150 for(const auto& c: contr) { s += c.cartesian_size(); }
151 return s;
152 }
153 size_t size() const {
154 size_t s = 0;
155 for(const auto& c: contr) { s += c.size(); }
156 return s;
157 }
158
159 size_t ncontr() const { return contr.size(); }
160 size_t nprim() const { return alpha.size(); }
161
162 bool operator==(const Shell& other) const {
163 return &other == this || (O == other.O && alpha == other.alpha && contr == other.contr);
164 }
165 bool operator!=(const Shell& other) const {
166 return not this->operator==(other);
167 }
168
169 static char am_symbol(size_t l) {
170 static char lsymb[] = "spdfghikmnoqrtuvwxyz";
171 assert(l<=19);
172 return lsymb[l];
173 }
174 static unsigned short am_symbol_to_l(char am_symbol) {
175 const char AM_SYMBOL = ::toupper(am_symbol);
176 switch (AM_SYMBOL) {
177 case 'S': return 0;
178 case 'P': return 1;
179 case 'D': return 2;
180 case 'F': return 3;
181 case 'G': return 4;
182 case 'H': return 5;
183 case 'I': return 6;
184 case 'K': return 7;
185 case 'M': return 8;
186 case 'N': return 9;
187 case 'O': return 10;
188 case 'Q': return 11;
189 case 'R': return 12;
190 case 'T': return 13;
191 case 'U': return 14;
192 case 'V': return 15;
193 case 'W': return 16;
194 case 'X': return 17;
195 case 'Y': return 18;
196 case 'Z': return 19;
197 default: throw "invalid angular momentum label";
198 }
199 }
200
202 typedef enum {false_value=0,true_value=1,default_value=2} value_t;
203 defaultable_boolean() : value_(default_value) {}
204 defaultable_boolean(bool v) : value_(static_cast<value_t>(v?1:0)) {}
205 bool is_default() const { return value_ == default_value; }
206 operator bool() const { assert(value_ != default_value); return value_ == true_value; }
207 private:
208 value_t value_;
209 };
210
216 static bool result{true};
217 if (not flag.is_default()) {
218 result = flag;
219 }
220 return result;
221 }
222
224 static const Shell& unit() {
225 static const Shell unitshell{make_unit()};
226 return unitshell;
227 }
228
231 real_t coeff_normalized(size_t c, size_t p) const {
232 const auto alpha = this->alpha.at(p);
233 assert(alpha >= 0.0);
234 const auto l = contr.at(c).l;
235 assert(l <= 15); // due to df_Kminus1[] a 64-bit integer type; kinda ridiculous restriction anyway
236
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;
243 }
244
246
250 Shell extract_primitive(size_t p, bool unit_normalized = true) const {
251 assert(p < nprim());
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.}});
256 }
257 return Shell({alpha[p]},
258 prim_contr,
259 O,
260 unit_normalized);
261 }
262
263 private:
264
265 // this makes a unit shell
266 struct make_unit{};
267 Shell(make_unit) :
268 alpha{0.0}, // exponent = 0
269 contr{{0, false, {1}}}, // contraction coefficient = 1
270 O{{0, 0, 0}}, // placed at origin
271 max_ln_coeff{0} {
272 }
273
277 void renorm() {
278 using libint2::math::df_Kminus1;
279 using std::pow;
280 const auto sqrt_Pi_cubed = real_t{5.56832799683170784528481798212};
281 const auto np = nprim();
282 for(auto& c: contr) {
283 assert(c.l <= 15); // due to df_Kminus1[] a 64-bit integer type; kinda ridiculous restriction anyway
284 for(auto p=0ul; p!=np; ++p) {
285 assert(alpha[p] >= 0);
286 if (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] ));
290
291 c.coeff[p] *= normalization_factor;
292 }
293 }
294
295 // need to force normalization to unity?
296 if (do_enforce_unit_normalization()) {
297 // compute the self-overlap of the , scale coefficients by its inverse square root
298 double norm{0};
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));
304 }
305 }
306 auto normalization_factor = 1 / sqrt(norm);
307 for(auto p=0ul; p!=np; ++p) {
308 c.coeff[p] *= normalization_factor;
309 }
310 }
311
312 }
313
314 update_max_ln_coeff();
315 }
316
317 void update_max_ln_coeff() {
318 // update max log coefficients
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])));
324 }
325 max_ln_coeff[p] = max_ln_c;
326 }
327 }
328
329 };
330
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;
333 os << " ";
334 for(const auto& c: sh.contr) {
335 os << " {l=" << c.l << ",sph=" << c.pure << "}";
336 }
337 os << std::endl;
338
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);
343 }
344 os << std::endl;
345 }
346
347 return os;
348 }
349
350 // clang-format off
357 enum class ScreeningMethod {
361 Original = 0x0001,
365 Conservative = 0x0010,
369 Schwarz = 0x0100,
373 SchwarzInf = 0x1000,
374 Invalid = 0x0000
375 };
376 // clang-format on
377
378 namespace detail {
379 inline ScreeningMethod& default_screening_method_accessor() {
380 static ScreeningMethod default_screening_method = ScreeningMethod::Original;
381 return default_screening_method;
382 }
383 }
384
385 inline ScreeningMethod default_screening_method() {
386 return detail::default_screening_method_accessor();
387 }
388
389 inline void default_screening_method(ScreeningMethod screening_method) {
390 detail::default_screening_method_accessor() = screening_method;
391 }
392
394 struct ShellPair {
395 typedef Shell::real_t real_t;
396
397 // clang-format off
400 real_t P[3];
401 real_t K;
404 real_t ln_scr;
405 int p1;
406 int p2;
407 };
408 // clang-format on
409
410 std::vector<PrimPairData> primpairs;
411 real_t AB[3];
412 real_t ln_prec = std::numeric_limits<real_t>::lowest();
413 ScreeningMethod screening_method_ = ScreeningMethod::Invalid;
414
415 ShellPair() : primpairs() { for(int i=0; i!=3; ++i) AB[i] = 0.; }
416
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.;
420 }
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);
423 }
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));
430 }
431
433 void reset() {
434 primpairs.clear();
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;
438 }
439
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);
444 }
445
447 template <typename Real> void init(const Shell& s1, const Shell& s2, Real ln_prec,
448 ScreeningMethod screening_method = ScreeningMethod::Original) {
449 assert(screening_method == ScreeningMethod::Original || screening_method == ScreeningMethod::Conservative);
450
451 using std::log;
452
453 primpairs.clear();
454
455 const auto& A = s1.O;
456 const auto& B = s2.O;
457 real_t AB2 = 0.;
458 for(int i=0; i!=3; ++i) {
459 AB[i] = A[i] - B[i];
460 AB2 += AB[i]*AB[i];
461 }
462
463 auto max_l = [](const Shell& s) {
464 using std::begin;
465 using std::end;
466 return std::max_element(begin(s.contr), end(s.contr), [](const Shell::Contraction& c1, const Shell::Contraction& c2) { return c1.l < c2.l; })->l;
467 };
468 const auto max_l1 = max_l(s1);
469 const auto max_l2 = max_l(s2);
470
471 const auto nprim1 = s1.alpha.size();
472 const auto nprim2 = s2.alpha.size();
473 size_t c = 0;
474 for(size_t p1=0; p1!=nprim1; ++p1) {
475 for(size_t p2=0; p2!=nprim2; ++p2) {
476
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;
481
482 const auto rho = a1 * a2 * oogamma;
483 const auto minus_rho_times_AB2 = -rho*AB2;
484 real_t ln_screen_fac = minus_rho_times_AB2 + s1.max_ln_coeff[p1] + s2.max_ln_coeff[p2];
485 if (screening_method == ScreeningMethod::Original && ln_screen_fac < ln_prec)
486 continue;
487
488 real_t P[3];
489 if (AB2 == 0.) { // this buys a bit more precision
490 P[0] = A[0];
491 P[1] = A[1];
492 P[2] = A[2];
493 } else {
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;
497 }
498
499 // conservative screening:
500 // - partitions the error among all primitive pairs (use \epsilon / nprim to screen, instead of \epsilon itself), and
501 // - accounts for the proper spherical gaussian prefactor in the integrals (namely, adds extra \sqrt{2 \pi^{52}}/\gamma_{ab} factor)
502 // - accounts for the nonspherical gaussians ... namely
503 // magnitude of primitive (ab|00) integral for nonzero L differs from that of (00|00) by the magnitude of:
504 // - (max_i|PA_i|)^La (max_i|PB_i|)^Lb when A-B separation is large, or
505 // - La! Lb! / gammap^(La+Lb) when the separation is small
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])),
512 max_l1);
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])),
517 max_l2);
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)));
526
527 constexpr decltype(rho) ln_sqrt_two_times_M_PI_to_1pt25 =
528 1.777485947591722872387900; // \ln(\sqrt{2} (\pi)^{5/4})
529 const auto ln_spherical_scr_extra_factor =
530 ln_sqrt_two_times_M_PI_to_1pt25 +
531 log(oogamma);
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)
536 continue;
537 }
538
539 primpairs.resize(c+1);
540 PrimPairData& p = primpairs[c];
541 p.ln_scr = ln_screen_fac;
542 p.p1 = p1;
543 p.p2 = p2;
544 constexpr decltype(rho) sqrt_two_times_M_PI_to_1pt25 =
545 5.9149671727956128778; // \sqrt{2} (\pi)^{5/4}
546 p.K = sqrt_two_times_M_PI_to_1pt25 * exp(minus_rho_times_AB2) * oogamma;
547 p.P[0] = P[0];
548 p.P[1] = P[1];
549 p.P[2] = P[2];
550 p.nonsph_screen_fac = nonspherical_scr_factor;
551 p.one_over_gamma = oogamma;
552
553 ++c;
554 }
555 }
556
557 this->ln_prec = ln_prec;
558 this->screening_method_ = screening_method;
559 }
560
562 template <typename Real, typename SchwarzFactorEvaluator> void init(const Shell& s1, const Shell& s2, Real ln_prec,
563 ScreeningMethod screening_method,
564 SchwarzFactorEvaluator&& schwarz_factor_evaluator) {
565 assert(screening_method == ScreeningMethod::Schwarz || screening_method == ScreeningMethod::SchwarzInf);
566
567 using std::log;
568
569 primpairs.clear();
570
571 const auto& A = s1.O;
572 const auto& B = s2.O;
573 real_t AB2 = 0.;
574 for(int i=0; i!=3; ++i) {
575 AB[i] = A[i] - B[i];
576 AB2 += AB[i]*AB[i];
577 }
578
579 const auto nprim1 = s1.alpha.size();
580 const auto nprim2 = s2.alpha.size();
581 const auto nprim12 = nprim1 * nprim2;
582 size_t c = 0;
583 for(size_t p1=0; p1!=nprim1; ++p1) {
584 for(size_t p2=0; p2!=nprim2; ++p2) {
585
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)
588 continue;
589
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;
594
595 const auto rho = a1 * a2 * oogamma;
596 const auto minus_rho_times_AB2 = -rho*AB2;
597
598 real_t P[3];
599 if (AB2 == 0.) { // this buys a bit more precision
600 P[0] = A[0];
601 P[1] = A[1];
602 P[2] = A[2];
603 } else {
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;
607 }
608
609 primpairs.resize(c+1);
610 PrimPairData& p = primpairs[c];
611 p.ln_scr = ln_screen_fac;
612 p.p1 = p1;
613 p.p2 = p2;
614 constexpr decltype(rho) sqrt_two_times_M_PI_to_1pt25 =
615 5.9149671727956128778; // \sqrt{2} (\pi)^{5/4}
616 p.K = sqrt_two_times_M_PI_to_1pt25 * exp(minus_rho_times_AB2) * oogamma;
617 p.P[0] = P[0];
618 p.P[1] = P[1];
619 p.P[2] = P[2];
620 p.nonsph_screen_fac = 0;
621 p.one_over_gamma = oogamma;
622
623 ++c;
624 }
625 }
626
627 this->ln_prec = ln_prec;
628 this->screening_method_ = screening_method;
629 }
630
631 };
632
633} // namespace libint2
634
635#endif /* _libint2_src_lib_libint_shell_h_ */
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