LIBINT 2.9.0
dfbs_generator.h
1/*
2 * Copyright (C) 2004-2024 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_dfbs_generator_h_
22#define _libint2_src_lib_libint_dfbs_generator_h_
23
24#include <libint2.h>
25#include <libint2/atom.h>
26#include <libint2/basis.h>
27#include <libint2/boys.h>
28#include <libint2/pivoted_cholesky.h>
29
30#include <Eigen/Dense>
31#include <Eigen/Eigenvalues>
32#include <algorithm>
33#include <cmath>
34
35namespace libint2 {
36
37namespace detail {
38
42inline std::vector<Shell> uncontract(const std::vector<Shell> &shells) {
43 std::vector<Shell> primitive_shells;
44 for (const auto &contracted_shell : shells) {
45 for (size_t p = 0; p < contracted_shell.nprim(); p++) {
46 const auto prim_shell = contracted_shell.extract_primitive(p, true);
47 // if dealing with generally contracted basis (e.g., cc-pvxz) represented
48 // as a segmented basis need to remove duplicates
49 if (std::find(primitive_shells.begin(), primitive_shells.end(),
50 prim_shell) == primitive_shells.end())
51 primitive_shells.emplace_back(std::move(prim_shell));
52 }
53 }
54 return primitive_shells;
55}
56
58inline double gamma_function(const double x) { return std::tgamma(x); }
59
69inline double alpha_eff(const Shell &shell1, const Shell &shell2, const int L) {
70 const auto alpha1 = shell1.alpha[0];
71 const auto alpha2 = shell2.alpha[0];
72 const auto l1 = shell1.contr[0].l;
73 const auto l2 = shell2.contr[0].l;
74 const auto prefactor =
75 std::pow((gamma_function(L + 2.) * gamma_function(l1 + l2 + 1.5)) /
76 (gamma_function(l1 + l2 + 2.) * gamma_function(L + 1.5)),
77 2.);
78 return prefactor * (alpha1 + alpha2);
79}
80
88inline std::vector<Shell> product_functions(
89 const std::vector<Shell> &primitive_shells) {
90 std::vector<Shell> product_functions;
91 for (size_t i = 0; i < primitive_shells.size(); ++i) {
92 for (size_t j = 0; j <= i; ++j) {
93 const auto li = primitive_shells[i].contr[0].l;
94 const auto lj = primitive_shells[j].contr[0].l;
95 for (auto L = std::abs(li - lj); L <= li + lj; L++) {
96 const auto alpha = libint2::svector<double>(
97 {alpha_eff(primitive_shells[i], primitive_shells[j], L)});
98 libint2::svector<Shell::Contraction> contr_;
99 Shell::Contraction contr1;
100 contr1.l = L;
101 contr1.pure = true; // libint2 needs solid harmonics for 2c2b integrals
102 contr1.coeff = {1.0};
103 contr_.push_back(contr1);
104 assert(primitive_shells[i].O == primitive_shells[j].O);
105 const auto shell = Shell(alpha, contr_, primitive_shells[i].O);
106 if (std::find(product_functions.begin(), product_functions.end(),
107 shell) == product_functions.end())
108 product_functions.emplace_back(shell);
109 }
110 }
111 }
112 return product_functions;
113}
114
116inline std::vector<size_t> map_shell_to_basis_function(
117 const std::vector<libint2::Shell> &shells) {
118 std::vector<size_t> result;
119 result.reserve(shells.size());
120
121 size_t n = 0;
122 for (auto &&shell : shells) {
123 result.push_back(n);
124 n += shell.size();
125 }
126
127 return result;
128}
129
134inline Eigen::MatrixXd compute_coulomb_matrix(
135 const std::vector<Shell> &shells) {
136 const auto n = nbf(shells);
137 Eigen::MatrixXd result = Eigen::MatrixXd::Zero(n, n);
138 using libint2::Engine;
139 const auto oper = libint2::Operator::coulomb;
140 const auto braket = libint2::BraKet::xs_xs;
141 Engine engine(oper, max_nprim(shells), max_l(shells), 0,
142 std::numeric_limits<scalar_type>::epsilon(),
143 libint2::default_params(oper), braket);
145 const auto shell2bf = map_shell_to_basis_function(shells);
146 const auto &buf = engine.results();
147 for (size_t s1 = 0; s1 != shells.size(); ++s1) {
148 auto bf1 = shell2bf[s1];
149 auto n1 = shells[s1].size();
150 for (size_t s2 = 0; s2 <= s1; ++s2) {
151 auto bf2 = shell2bf[s2];
152 auto n2 = shells[s2].size();
153 engine.compute(shells[s1], shells[s2]);
154 Eigen::Map<const Eigen::MatrixXd> buf_mat(buf[0], n1, n2);
155 result.block(bf1, bf2, n1, n2) = buf_mat;
156 if (s1 != s2) result.block(bf2, bf1, n2, n1) = buf_mat.transpose();
157 }
158 }
159 return result;
160}
161
166inline std::vector<std::vector<Shell>> split_by_L(
167 const std::vector<Shell> &shells) {
168 int lmax = max_l(shells);
169 std::vector<std::vector<Shell>> sorted_shells;
170 sorted_shells.resize(lmax + 1);
171 for (auto &&shell : shells) {
172 auto l = shell.contr[0].l;
173 sorted_shells[l].push_back(shell);
174 }
175 return sorted_shells;
176}
177
189inline std::vector<Shell> pivoted_cholesky_in_L(
190 const std::vector<Shell> &shells, const double cholesky_threshold) {
191 const auto n = shells.size(); // number of shells
192 std::vector<size_t>
193 shell_indices; // hash map of basis function indices to shell indices
194 const auto L = shells[0].contr[0].l; // all shells must have same L
195 const auto nbf = libint2::nbf(
196 shells); // total number of basis functions in vector of shells
197 for (size_t i = 0; i < n; ++i) {
198 for (size_t j = 0; j < 2 * L + 1;
199 ++j) // 2L+1 since libint2 strictly uses solid harmonics for 2c2b
200 // integrals
201 shell_indices.push_back(i);
202 }
203 assert(shell_indices.size() == nbf);
204 const auto C = compute_coulomb_matrix(shells);
205 std::vector<size_t> pivot(nbf);
206 for (auto i = 0; i < nbf; ++i) {
207 pivot[i] = i;
208 }
209 // set pivot indices in ascending order of off diagonal elements of Coulomb
210 // matrix see Phys. Rev. A 101, 032504 (Accurate reproduction of strongly
211 // repulsive interatomic potentials)
212 Eigen::MatrixXd C_off_diag = C;
213 auto col_sum = C_off_diag.colwise().sum();
214 // sort pivot indices in ascending order of column sums
215 std::sort(pivot.begin(), pivot.end(), [&col_sum](size_t i1, size_t i2) {
216 return col_sum[i1] < col_sum[i2];
217 });
218 // compute Cholesky decomposition
219 const auto reduced_pivots = pivoted_cholesky(C, cholesky_threshold, pivot);
220
221 std::vector<Shell> reduced_shells;
222 for (size_t i = 0; i < reduced_pivots.size(); ++i) {
223 // check if the reduced shell is already in reduced shells
224 if (std::find(reduced_shells.begin(), reduced_shells.end(),
225 shells[shell_indices[reduced_pivots[i]]]) ==
226 reduced_shells.end())
227 reduced_shells.push_back(shells[shell_indices[reduced_pivots[i]]]);
228 }
229 return reduced_shells;
230}
231} // namespace detail
232
239 public:
250 DFBasisSetGenerator(std::string obs_name, const Atom &atom,
251 const double cholesky_threshold = 1e-7) {
252 // get AO basis shells for each atom
253 const auto atom_bs = BasisSet(obs_name, {atom});
254 const auto obs_shells = atom_bs.shells();
255 // get primitive shells from AO functions
256 const auto primitive_shells = detail::uncontract(obs_shells);
257 // compute candidate shells
258 candidate_shells_ = detail::product_functions(primitive_shells);
259 cholesky_threshold_ = cholesky_threshold;
260 }
261
267 DFBasisSetGenerator(const std::vector<Shell> &shells,
268 const double cholesky_threshold = 1e-7) {
269 const auto primitive_shells = detail::uncontract(shells);
270 candidate_shells_ = detail::product_functions(primitive_shells);
271 cholesky_threshold_ = cholesky_threshold;
272 }
273
274 DFBasisSetGenerator() = default;
275
276 ~DFBasisSetGenerator() = default;
277
279 std::vector<Shell> candidate_shells() { return candidate_shells_; }
280
285 std::vector<Shell> reduced_shells() {
286 if (reduced_shells_computed_)
287 return reduced_shells_;
288 else {
289 const auto candidate_splitted_in_L =
290 detail::split_by_L(candidate_shells_);
291 for (size_t i = 0; i < candidate_splitted_in_L.size(); ++i) {
292 std::vector<Shell> reduced_shells_L;
293 if (candidate_splitted_in_L[i].size() > 1)
294 reduced_shells_L = detail::pivoted_cholesky_in_L(
295 candidate_splitted_in_L[i], cholesky_threshold_);
296 else
297 reduced_shells_L = candidate_splitted_in_L[i];
298 reduced_shells_.insert(reduced_shells_.end(), reduced_shells_L.begin(),
299 reduced_shells_L.end());
300 }
301 reduced_shells_computed_ = true;
302 }
303 return reduced_shells_;
304 }
305
310 const BasisSet reduced_basis() { return BasisSet(reduced_shells()); }
311
312 private:
313 double cholesky_threshold_;
314 std::vector<Shell> candidate_shells_; // full set of product functions
315 std::vector<Shell> reduced_shells_; // reduced set of product functions
316 bool reduced_shells_computed_ = false;
317};
318
319} // namespace libint2
320
321#endif /* _libint2_src_lib_libint_dfbs_generator_h_ */
This class produces density fitting basis sets for an atom from products of AO basis functions and el...
Definition dfbs_generator.h:238
std::vector< Shell > reduced_shells()
returns a set of shells reduced via pivoted Cholesky decomposition of the Coulomb matrix of the produ...
Definition dfbs_generator.h:285
std::vector< Shell > candidate_shells()
returns the candidate shells (full set of product functions)
Definition dfbs_generator.h:279
const BasisSet reduced_basis()
returns a BasisSet of shells reduced via pivoted Cholesky decomposition of the Coulomb matrix of the ...
Definition dfbs_generator.h:310
DFBasisSetGenerator(std::string obs_name, const Atom &atom, const double cholesky_threshold=1e-7)
constructor for DFBasisSetGenerator class, generates density fitting basis set from products of AO ba...
Definition dfbs_generator.h:250
DFBasisSetGenerator(const std::vector< Shell > &shells, const double cholesky_threshold=1e-7)
constructor for DFBasisSetGenerator class, generates density fitting basis set from products of AO sh...
Definition dfbs_generator.h:267
std::vector< Shell > uncontract(const std::vector< Shell > &shells)
Uncontracts a set of shells.
Definition dfbs_generator.h:42
double alpha_eff(const Shell &shell1, const Shell &shell2, const int L)
Computes an effective exponent for a product of two primitive gaussians as as described in J.
Definition dfbs_generator.h:69
std::vector< Shell > pivoted_cholesky_in_L(const std::vector< Shell > &shells, const double cholesky_threshold)
Computes the reduced set of product functions via pivoted Cholesky decomposition as described in J.
Definition dfbs_generator.h:189
std::vector< size_t > map_shell_to_basis_function(const std::vector< libint2::Shell > &shells)
returns a hash map of shell indices to basis function indices
Definition dfbs_generator.h:116
double gamma_function(const double x)
returns
Definition dfbs_generator.h:58
std::vector< std::vector< Shell > > split_by_L(const std::vector< Shell > &shells)
Splits a set of shells by angular momentum.
Definition dfbs_generator.h:166
std::vector< Shell > product_functions(const std::vector< Shell > &primitive_shells)
Creates a set of product functions from a set of primitive shells.
Definition dfbs_generator.h:88
Eigen::MatrixXd compute_coulomb_matrix(const std::vector< Shell > &shells)
Computes the Coulomb matrix for a set of shells.
Definition dfbs_generator.h:134
Defaults definitions for various parameters assumed by Libint.
Definition algebra.cc:24
@ Conservative
conservative screening:
std::vector< size_t > pivoted_cholesky(const Eigen::MatrixXd &A, const double tolerance, const std::vector< size_t > &pivot)
computes the pivoted Cholesky decomposition of a symmetric positive definite matrix
Definition pivoted_cholesky.h:36
__libint2_engine_inline libint2::any default_params(const Operator &oper)
the runtime version of operator_traits<oper>::default_params()
Definition engine.impl.h:116
Definition atom.h:40
contracted Gaussian = angular momentum + sph/cart flag + contraction coefficients
Definition shell.h:725
generally-contracted Solid-Harmonic/Cartesion Gaussian Shell
Definition shell.h:720
svector< Contraction > contr
contractions
Definition shell.h:742
svector< real_t > alpha
exponents
Definition shell.h:741