GQCP
Loading...
Searching...
No Matches
IntegralCalculator.hpp
Go to the documentation of this file.
1// This file is part of GQCG-GQCP.
2//
3// Copyright (C) 2017-2020 the GQCG developers
4//
5// GQCG-GQCP is free software: you can redistribute it and/or modify
6// it under the terms of the GNU Lesser General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// GQCG-GQCP is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU Lesser General Public License for more details.
14//
15// You should have received a copy of the GNU Lesser General Public License
16// along with GQCG-GQCP. If not, see <http://www.gnu.org/licenses/>.
17
18#pragma once
19
20
30#include "Utilities/aliases.hpp"
31
32#include <algorithm>
33#include <array>
34#include <memory>
35
36
37namespace GQCP {
38
39
44public:
45 /*
46 * PUBLIC METHODS
47 */
48
60 template <typename Shell, size_t N, typename IntegralScalar>
61 static auto calculate(BaseOneElectronIntegralEngine<Shell, N, IntegralScalar>& engine, const ShellSet<Shell>& left_shell_set, const ShellSet<Shell>& right_shell_set) -> std::array<MatrixX<IntegralScalar>, N> {
62
63 // Initialize the N components of the matrix representations of the operator.
64 const auto nbf_left = left_shell_set.numberOfBasisFunctions();
65 const auto nbf_right = right_shell_set.numberOfBasisFunctions();
66
67 std::array<MatrixX<IntegralScalar>, N> components;
68 for (auto& component : components) {
69 component = MatrixX<IntegralScalar>::Zero(nbf_left, nbf_right);
70 }
71
72
73 // Loop over all left and right shells and let the engine calculate the integrals over the pairs of shells.
74 const auto nsh_left = left_shell_set.numberOfShells();
75 const auto left_shells = left_shell_set.asVector();
76 const auto nsh_right = right_shell_set.numberOfShells();
77 const auto right_shells = right_shell_set.asVector();
78
79 for (size_t left_shell_index = 0; left_shell_index < nsh_left; left_shell_index++) {
80 const auto left_bf_index = left_shell_set.basisFunctionIndex(left_shell_index);
81 const auto left_shell = left_shells[left_shell_index];
82
83 for (size_t right_shell_index = 0; right_shell_index < nsh_right; right_shell_index++) {
84 const auto right_bf_index = right_shell_set.basisFunctionIndex(right_shell_index);
85 const auto right_shell = right_shells[right_shell_index];
86
87 const auto buffer = engine.calculate(left_shell, right_shell);
88
89 // Only if the integrals are not all zero, place them inside the full matrices.
90 if (buffer->areIntegralsAllZero()) {
91 continue;
92 }
93 buffer->emplace(components, left_bf_index, right_bf_index);
94 } // right shells loop
95 } // left shells loop
96
97 return components;
98 }
99
100
112 template <typename Shell, size_t N, typename IntegralScalar>
113 static auto calculate(BaseTwoElectronIntegralEngine<Shell, N, IntegralScalar>& engine, const ShellSet<Shell>& left_shell_set, const ShellSet<Shell>& right_shell_set) -> std::array<Tensor<IntegralScalar, 4>, N> {
114
115 // Initialize the N components of the matrix representations of the operator.
116 const auto nbf_left = left_shell_set.numberOfBasisFunctions();
117 const auto nbf_right = right_shell_set.numberOfBasisFunctions();
118
119 std::array<Tensor<IntegralScalar, 4>, N> components;
120 for (auto& component : components) {
121 component = Tensor<IntegralScalar, 4>(nbf_left, nbf_left, nbf_right, nbf_right);
122 component.setZero();
123 }
124
125
126 // Loop over all left and right shells and let the engine calculate the integrals over the 4-tuple of shells.
127 const auto nsh_left = left_shell_set.numberOfShells();
128 const auto left_shells = left_shell_set.asVector();
129 const auto nsh_right = right_shell_set.numberOfShells();
130 const auto right_shells = right_shell_set.asVector();
131
132 for (size_t left_shell_index1 = 0; left_shell_index1 < nsh_left; left_shell_index1++) {
133 const auto left_bf1_index = left_shell_set.basisFunctionIndex(left_shell_index1);
134 const auto left_shell1 = left_shells[left_shell_index1];
135
136 for (size_t left_shell_index2 = 0; left_shell_index2 < nsh_left; left_shell_index2++) {
137 const auto left_bf2_index = left_shell_set.basisFunctionIndex(left_shell_index2);
138 const auto left_shell2 = left_shells[left_shell_index2];
139
140 for (size_t right_shell_index1 = 0; right_shell_index1 < nsh_right; right_shell_index1++) {
141 const auto right_bf1_index = right_shell_set.basisFunctionIndex(right_shell_index1);
142 const auto right_shell1 = right_shells[right_shell_index1];
143
144 for (size_t right_shell_index2 = 0; right_shell_index2 < nsh_right; right_shell_index2++) {
145 const auto right_bf2_index = right_shell_set.basisFunctionIndex(right_shell_index2);
146 const auto right_shell2 = right_shells[right_shell_index2];
147
148 const auto buffer = engine.calculate(left_shell1, left_shell2, right_shell1, right_shell2);
149
150 // Only if the integrals are not all zero, place them inside the full matrices
151 if (buffer->areIntegralsAllZero()) {
152 continue;
153 }
154 buffer->emplace(components, left_bf1_index, left_bf2_index, right_bf1_index, right_bf2_index); // place the calculated integrals inside the full tensors
155
156 } // sh4_index
157 } // right_shell_index1
158 } // left_shell_index2
159 } // left_shell_index1
160
161 return components;
162 }
163
164
165 /*
166 * PUBLIC METHODS - LIBINT2 INTEGRALS
167 */
168
180 template <typename FQOneElectronOperator>
181 static Matrix<double> calculateLibintIntegrals(const FQOneElectronOperator& fq_one_op, const ScalarBasis<GTOShell>& left_scalar_basis, const ScalarBasis<GTOShell>& right_scalar_basis) {
182
183 const auto left_shell_set = left_scalar_basis.shellSet();
184 const auto right_shell_set = right_scalar_basis.shellSet();
185
186 // Construct the libint engine
187 const auto max_nprim = std::max(left_shell_set.maximumNumberOfPrimitives(), right_shell_set.maximumNumberOfPrimitives());
188 const auto max_l = std::max(left_shell_set.maximumAngularMomentum(), right_shell_set.maximumAngularMomentum());
189 auto engine = IntegralEngine::Libint(fq_one_op, max_nprim, max_l);
190
191
192 // Calculate the integrals using the engine
193 const auto integrals = IntegralCalculator::calculate(engine, left_shell_set, right_shell_set);
194 return integrals[0];
195 }
196
197
208 template <typename FQOneElectronOperator>
209 static SquareMatrix<double> calculateLibintIntegrals(const FQOneElectronOperator& fq_one_op, const ScalarBasis<GTOShell>& scalar_basis) {
210
211 return SquareMatrix<double>(IntegralCalculator::calculateLibintIntegrals(fq_one_op, scalar_basis, scalar_basis)); // the same scalar basis appear on the left and right of the operator
212 }
213
214
224 static std::array<Matrix<double>, 3> calculateLibintIntegrals(const ElectronicDipoleOperator& fq_one_op, const ScalarBasis<GTOShell>& left_scalar_basis, const ScalarBasis<GTOShell>& right_scalar_basis) {
225
226 const auto left_shell_set = left_scalar_basis.shellSet();
227 const auto right_shell_set = right_scalar_basis.shellSet();
228
229 // Construct the libint engine
230 const auto max_nprim = std::max(left_shell_set.maximumNumberOfPrimitives(), right_shell_set.maximumNumberOfPrimitives());
231 const auto max_l = std::max(left_shell_set.maximumAngularMomentum(), right_shell_set.maximumAngularMomentum());
232 auto engine = IntegralEngine::Libint(fq_one_op, max_nprim, max_l);
233
234
235 // Calculate the integrals using the engine
236 const auto integrals = IntegralCalculator::calculate(engine, left_shell_set, right_shell_set);
237 return {integrals[0], integrals[1], integrals[2]};
238 }
239
240
249 static std::array<SquareMatrix<double>, 3> calculateLibintIntegrals(const ElectronicDipoleOperator& fq_one_op, const ScalarBasis<GTOShell>& scalar_basis) {
250
251 // Convert the array of Matrix to an array of SquareMatrix
252 const auto calculated_components = IntegralCalculator::calculateLibintIntegrals(fq_one_op, scalar_basis, scalar_basis); // the same scalar basis appear on the left and right of the operator
253
254 std::array<SquareMatrix<double>, 3> converted_components {};
255 for (size_t i = 0; i < 3; i++) {
256 converted_components[i] = SquareMatrix<double>(calculated_components[i]);
257 }
258 return converted_components;
259 }
260
261
271
272 return SquareRankFourTensor<double>(IntegralCalculator::calculateLibintIntegrals(fq_two_op, scalar_basis, scalar_basis)); // the same scalar basis appear on the left and right of the operator
273 }
274
275
285 static Tensor<double, 4> calculateLibintIntegrals(const CoulombRepulsionOperator& fq_two_op, const ScalarBasis<GTOShell>& left_scalar_basis, const ScalarBasis<GTOShell>& right_scalar_basis) {
286
287 const auto left_shell_set = left_scalar_basis.shellSet();
288 const auto right_shell_set = right_scalar_basis.shellSet();
289
290 // Construct the libint engine
291 const auto max_nprim = std::max(left_shell_set.maximumNumberOfPrimitives(), right_shell_set.maximumNumberOfPrimitives());
292 const auto max_l = std::max(left_shell_set.maximumAngularMomentum(), right_shell_set.maximumAngularMomentum());
293 auto engine = IntegralEngine::Libint(fq_two_op, max_nprim, max_l);
294
295
296 // Calculate the integrals using the engine
297 const auto integrals = IntegralCalculator::calculate(engine, left_shell_set, right_shell_set);
298 return integrals[0];
299 }
300
301
302 /*
303 * PUBLIC METHODS - LIBCINT INTEGRALS
304 * Note that the Libcint integrals should only be used for Cartesian ShellSets
305 */
306
319 template <typename FQOneElectronOperator>
320 static SquareMatrix<double> calculateLibcintIntegrals(const FQOneElectronOperator& fq_one_op, const ScalarBasis<GTOShell>& scalar_basis) {
321
322 const auto shell_set = scalar_basis.shellSet();
323
324 auto engine = IntegralEngine::Libcint(fq_one_op, shell_set);
325 const auto integrals = IntegralCalculator::calculate(engine, shell_set, shell_set);
326 return integrals[0];
327 }
328
329
340 static std::array<SquareMatrix<double>, 3> calculateLibcintIntegrals(const ElectronicDipoleOperator& fq_one_op, const ScalarBasis<GTOShell>& scalar_basis) {
341
342 const auto shell_set = scalar_basis.shellSet();
343
344 auto engine = IntegralEngine::Libcint(fq_one_op, shell_set);
345 const auto integrals = IntegralCalculator::calculate(engine, shell_set, shell_set);
346 return {integrals[0], integrals[1], integrals[2]};
347 }
348
349
361
362 const auto shell_set = scalar_basis.shellSet();
363
364 auto engine = IntegralEngine::Libcint(fq_op, shell_set);
365 const auto integrals = IntegralCalculator::calculate(engine, shell_set, shell_set);
366 return integrals[0];
367 }
368};
369
370
371} // namespace GQCP
Definition: BaseOneElectronIntegralEngine.hpp:37
Definition: BaseTwoElectronIntegralEngine.hpp:37
Definition: CoulombRepulsionOperator.hpp:31
Definition: ElectronicDipoleOperator.hpp:33
Definition: IntegralCalculator.hpp:43
static SquareMatrix< double > calculateLibcintIntegrals(const FQOneElectronOperator &fq_one_op, const ScalarBasis< GTOShell > &scalar_basis)
Definition: IntegralCalculator.hpp:320
static std::array< SquareMatrix< double >, 3 > calculateLibintIntegrals(const ElectronicDipoleOperator &fq_one_op, const ScalarBasis< GTOShell > &scalar_basis)
Definition: IntegralCalculator.hpp:249
static Matrix< double > calculateLibintIntegrals(const FQOneElectronOperator &fq_one_op, const ScalarBasis< GTOShell > &left_scalar_basis, const ScalarBasis< GTOShell > &right_scalar_basis)
Definition: IntegralCalculator.hpp:181
static std::array< SquareMatrix< double >, 3 > calculateLibcintIntegrals(const ElectronicDipoleOperator &fq_one_op, const ScalarBasis< GTOShell > &scalar_basis)
Definition: IntegralCalculator.hpp:340
static SquareMatrix< double > calculateLibintIntegrals(const FQOneElectronOperator &fq_one_op, const ScalarBasis< GTOShell > &scalar_basis)
Definition: IntegralCalculator.hpp:209
static SquareRankFourTensor< double > calculateLibintIntegrals(const CoulombRepulsionOperator &fq_two_op, const ScalarBasis< GTOShell > &scalar_basis)
Definition: IntegralCalculator.hpp:270
static Tensor< double, 4 > calculateLibintIntegrals(const CoulombRepulsionOperator &fq_two_op, const ScalarBasis< GTOShell > &left_scalar_basis, const ScalarBasis< GTOShell > &right_scalar_basis)
Definition: IntegralCalculator.hpp:285
static SquareRankFourTensor< double > calculateLibcintIntegrals(const CoulombRepulsionOperator &fq_op, const ScalarBasis< GTOShell > &scalar_basis)
Definition: IntegralCalculator.hpp:360
static auto calculate(BaseTwoElectronIntegralEngine< Shell, N, IntegralScalar > &engine, const ShellSet< Shell > &left_shell_set, const ShellSet< Shell > &right_shell_set) -> std::array< Tensor< IntegralScalar, 4 >, N >
Definition: IntegralCalculator.hpp:113
static auto calculate(BaseOneElectronIntegralEngine< Shell, N, IntegralScalar > &engine, const ShellSet< Shell > &left_shell_set, const ShellSet< Shell > &right_shell_set) -> std::array< MatrixX< IntegralScalar >, N >
Definition: IntegralCalculator.hpp:61
static std::array< Matrix< double >, 3 > calculateLibintIntegrals(const ElectronicDipoleOperator &fq_one_op, const ScalarBasis< GTOShell > &left_scalar_basis, const ScalarBasis< GTOShell > &right_scalar_basis)
Definition: IntegralCalculator.hpp:224
static auto Libint(const CoulombRepulsionOperator &op, const size_t max_nprim, const size_t max_l) -> LibintTwoElectronIntegralEngine< CoulombRepulsionOperator::NumberOfComponents >
Definition: IntegralEngine.cpp:35
static auto Libcint(const CoulombRepulsionOperator &op, const ShellSet< GTOShell > &shell_set) -> LibcintTwoElectronIntegralEngine< GTOShell, CoulombRepulsionOperator::NumberOfComponents, double >
Definition: IntegralEngine.cpp:103
Definition: Matrix.hpp:47
Definition: ScalarBasis.hpp:41
const ShellSet< Shell > & shellSet() const
Definition: ScalarBasis.hpp:140
Definition: ShellSet.hpp:41
Definition: SquareMatrix.hpp:39
Definition: SquareRankFourTensor.hpp:36
Definition: Tensor.hpp:46
Definition: BaseOneElectronIntegralBuffer.hpp:25