GQCP
Loading...
Searching...
No Matches
PrimitiveCoulombRepulsionIntegralEngine.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
26
27#include <boost/math/constants/constants.hpp>
28
29#include <cmath>
30
31
32namespace GQCP {
33
34
40template <typename _Shell>
43public:
44 // The type of shell that this integral engine is related to.
45 using Shell = _Shell;
46
47 // The type of primitive that underlies the type of shell.
48 using Primitive = typename Shell::Primitive;
49
50 // The scalar representation of a nuclear attraction integral.
52
53
54public:
55 /*
56 * MARK: CartesianGTO integrals
57 */
58
69 template <typename Z = Shell>
71
72 // Prepare some variables. Those with an extra underscore represent the 'primed' indices in the notes.
73 const auto i = static_cast<int>(left1.cartesianExponents().value(CartesianDirection::x));
74 const auto k = static_cast<int>(left1.cartesianExponents().value(CartesianDirection::y));
75 const auto m = static_cast<int>(left1.cartesianExponents().value(CartesianDirection::z));
76
77 const auto j = static_cast<int>(left2.cartesianExponents().value(CartesianDirection::x));
78 const auto l = static_cast<int>(left2.cartesianExponents().value(CartesianDirection::y));
79 const auto n = static_cast<int>(left2.cartesianExponents().value(CartesianDirection::z));
80
81 const auto i_ = static_cast<int>(right1.cartesianExponents().value(CartesianDirection::x));
82 const auto k_ = static_cast<int>(right1.cartesianExponents().value(CartesianDirection::y));
83 const auto m_ = static_cast<int>(right1.cartesianExponents().value(CartesianDirection::z));
84
85 const auto j_ = static_cast<int>(right2.cartesianExponents().value(CartesianDirection::x));
86 const auto l_ = static_cast<int>(right2.cartesianExponents().value(CartesianDirection::y));
87 const auto n_ = static_cast<int>(right2.cartesianExponents().value(CartesianDirection::z));
88
89 const auto a = left1.gaussianExponent();
90 const auto b = left2.gaussianExponent();
91 const auto c = right1.gaussianExponent();
92 const auto d = right2.gaussianExponent();
93
94 const auto K_x = left1.center()(CartesianDirection::x);
95 const auto K_y = left1.center()(CartesianDirection::y);
96 const auto K_z = left1.center()(CartesianDirection::z);
97
98 const auto L_x = left2.center()(CartesianDirection::x);
99 const auto L_y = left2.center()(CartesianDirection::y);
100 const auto L_z = left2.center()(CartesianDirection::z);
101
102 const auto M_x = right1.center()(CartesianDirection::x);
103 const auto M_y = right1.center()(CartesianDirection::y);
104 const auto M_z = right1.center()(CartesianDirection::z);
105
106 const auto N_x = right2.center()(CartesianDirection::x);
107 const auto N_y = right2.center()(CartesianDirection::y);
108 const auto N_z = right2.center()(CartesianDirection::z);
109
110
111 // Prepare the McMurchie-Davidson coefficients.
112 const McMurchieDavidsonCoefficient E_x {K_x, a, L_x, b};
113 const McMurchieDavidsonCoefficient E_y {K_y, a, L_y, b};
114 const McMurchieDavidsonCoefficient E_z {K_z, a, L_z, b};
115
116 const McMurchieDavidsonCoefficient E_x_ {M_x, c, N_x, d};
117 const McMurchieDavidsonCoefficient E_y_ {M_y, c, N_y, d};
118 const McMurchieDavidsonCoefficient E_z_ {M_z, c, N_z, d};
119
120
121 // Prepare the Hermite Coulomb integral.
122 const double p = a + b;
123 const double q = c + d;
124 const double alpha = p * q / (p + q);
125
126 const Vector<double, 3> P {E_x.centerOfMass(), E_y.centerOfMass(), E_z.centerOfMass()};
127 const Vector<double, 3> Q {E_x_.centerOfMass(), E_y_.centerOfMass(), E_z_.centerOfMass()};
128
129 const HermiteCoulombIntegral R {alpha, P, Q};
130
131
132 // Calculate the Coulomb repulsion integrals over the primitives.
133 double integral {};
134 for (int t = 0; t <= i + j; t++) {
135 for (int u = 0; u <= k + l; u++) {
136 for (int v = 0; v <= m + n; v++) {
137 for (int tau = 0; tau <= i_ + j_; tau++) {
138 for (int mu = 0; mu <= k_ + l_; mu++) {
139 for (int nu = 0; nu <= m_ + n_; nu++) {
140 // Add the contribution to the integral. The prefactor will be applied at the end.
141 integral += E_x(i, j, t) * E_y(k, l, u) * E_z(m, n, v) *
142 E_x_(i_, j_, tau) * E_y_(k_, l_, mu) * E_z_(m_, n_, nu) *
143 std::pow(-1, tau + mu + nu) * R(0, t + tau, u + mu, v + nu);
144 }
145 }
146 }
147 }
148 }
149 }
150
151 return 2 * std::pow(boost::math::constants::pi<double>(), 2.5) / (p * q * std::sqrt(p + q)) * integral;
152 }
153
154
155 /*
156 * MARK: CartesianGTO integrals
157 */
158
169 template <typename Z = Shell>
171
172 // Prepare some variables. Those with an extra underscore represent the 'primed' indices in the notes.
173 const auto i = static_cast<int>(left1.cartesianGTO().cartesianExponents().value(CartesianDirection::x));
174 const auto k = static_cast<int>(left1.cartesianGTO().cartesianExponents().value(CartesianDirection::y));
175 const auto m = static_cast<int>(left1.cartesianGTO().cartesianExponents().value(CartesianDirection::z));
176
177 const auto j = static_cast<int>(left2.cartesianGTO().cartesianExponents().value(CartesianDirection::x));
178 const auto l = static_cast<int>(left2.cartesianGTO().cartesianExponents().value(CartesianDirection::y));
179 const auto n = static_cast<int>(left2.cartesianGTO().cartesianExponents().value(CartesianDirection::z));
180
181 const auto i_ = static_cast<int>(right1.cartesianGTO().cartesianExponents().value(CartesianDirection::x));
182 const auto k_ = static_cast<int>(right1.cartesianGTO().cartesianExponents().value(CartesianDirection::y));
183 const auto m_ = static_cast<int>(right1.cartesianGTO().cartesianExponents().value(CartesianDirection::z));
184
185 const auto j_ = static_cast<int>(right2.cartesianGTO().cartesianExponents().value(CartesianDirection::x));
186 const auto l_ = static_cast<int>(right2.cartesianGTO().cartesianExponents().value(CartesianDirection::y));
187 const auto n_ = static_cast<int>(right2.cartesianGTO().cartesianExponents().value(CartesianDirection::z));
188
189 const auto a = left1.cartesianGTO().gaussianExponent();
190 const auto b = left2.cartesianGTO().gaussianExponent();
191 const auto c = right1.cartesianGTO().gaussianExponent();
192 const auto d = right2.cartesianGTO().gaussianExponent();
193
194 const auto K_x = left1.cartesianGTO().center()(CartesianDirection::x);
195 const auto K_y = left1.cartesianGTO().center()(CartesianDirection::y);
196 const auto K_z = left1.cartesianGTO().center()(CartesianDirection::z);
197
198 const auto L_x = left2.cartesianGTO().center()(CartesianDirection::x);
199 const auto L_y = left2.cartesianGTO().center()(CartesianDirection::y);
200 const auto L_z = left2.cartesianGTO().center()(CartesianDirection::z);
201
202 const auto M_x = right1.cartesianGTO().center()(CartesianDirection::x);
203 const auto M_y = right1.cartesianGTO().center()(CartesianDirection::y);
204 const auto M_z = right1.cartesianGTO().center()(CartesianDirection::z);
205
206 const auto N_x = right2.cartesianGTO().center()(CartesianDirection::x);
207 const auto N_y = right2.cartesianGTO().center()(CartesianDirection::y);
208 const auto N_z = right2.cartesianGTO().center()(CartesianDirection::z);
209
210
211 const Vector<double, 3> k1 = left2.kVector() - left1.kVector(); // The k-vector of the left London overlap distribution.
212 const Vector<double, 3> k2 = right2.kVector() - right1.kVector(); // The k-vector of the rightLondon overlap distribution.
213
214
215 // Prepare the McMurchie-Davidson coefficients.
216 const McMurchieDavidsonCoefficient E_x {K_x, a, L_x, b};
217 const McMurchieDavidsonCoefficient E_y {K_y, a, L_y, b};
218 const McMurchieDavidsonCoefficient E_z {K_z, a, L_z, b};
219
220 const McMurchieDavidsonCoefficient E_x_ {M_x, c, N_x, d};
221 const McMurchieDavidsonCoefficient E_y_ {M_y, c, N_y, d};
222 const McMurchieDavidsonCoefficient E_z_ {M_z, c, N_z, d};
223
224
225 // Prepare the double London Hermite Coulomb integral.
226 const double p = a + b;
227 const double q = c + d;
228
229 const Vector<double, 3> P {E_x.centerOfMass(), E_y.centerOfMass(), E_z.centerOfMass()};
230 const Vector<double, 3> Q {E_x_.centerOfMass(), E_y_.centerOfMass(), E_z_.centerOfMass()};
231
232 const DoubleLondonHermiteCoulombIntegral R {k1, p, P, k2, q, Q};
233
234
235 // Calculate the Coulomb repulsion integrals over the primitives.
236 complex integral {};
237 for (int t = 0; t <= i + j; t++) {
238 for (int u = 0; u <= k + l; u++) {
239 for (int v = 0; v <= m + n; v++) {
240 for (int tau = 0; tau <= i_ + j_; tau++) {
241 for (int mu = 0; mu <= k_ + l_; mu++) {
242 for (int nu = 0; nu <= m_ + n_; nu++) {
243 // Add the contribution to the integral. The prefactor will be applied at the end.
244 integral += E_x(i, j, t) * E_y(k, l, u) * E_z(m, n, v) *
245 E_x_(i_, j_, tau) * E_y_(k_, l_, mu) * E_z_(m_, n_, nu) *
246 R(0, t, u, v, tau, mu, nu);
247 }
248 }
249 }
250 }
251 }
252 }
253
254 return 2 * std::pow(boost::math::constants::pi<double>(), 2.5) / (p * q * std::sqrt(p + q)) *
255 std::exp(-k1.squaredNorm() / (4 * p)) * std::exp(-k2.squaredNorm() / (4 * q)) *
256 integral;
257 }
258};
259
260
261} // namespace GQCP
Definition: BaseScalarPrimitiveIntegralEngine.hpp:30
Definition: CartesianGTO.hpp:38
const Vector< double, 3 > & center() const
Definition: CartesianGTO.hpp:129
double gaussianExponent() const
Definition: CartesianGTO.hpp:139
const CartesianExponents & cartesianExponents() const
Definition: CartesianGTO.hpp:112
Definition: DoubleLondonHermiteCoulombIntegral.hpp:31
Definition: HermiteCoulombIntegral.hpp:30
Definition: LondonCartesianGTO.hpp:38
Vector< double, 3 > kVector() const
Definition: LondonCartesianGTO.cpp:45
const CartesianGTO & cartesianGTO() const
Definition: LondonCartesianGTO.hpp:89
Definition: Matrix.hpp:47
Definition: McMurchieDavidsonCoefficient.hpp:30
Definition: PrimitiveCoulombRepulsionIntegralEngine.hpp:42
enable_if_t< std::is_same< Z, LondonGTOShell >::value, IntegralScalar > calculate(const LondonCartesianGTO &left1, const LondonCartesianGTO &left2, const LondonCartesianGTO &right1, const LondonCartesianGTO &right2)
Definition: PrimitiveCoulombRepulsionIntegralEngine.hpp:170
product_t< CoulombRepulsionOperator::Scalar, typename Primitive::OutputType > IntegralScalar
Definition: PrimitiveCoulombRepulsionIntegralEngine.hpp:51
typename Shell::Primitive Primitive
Definition: PrimitiveCoulombRepulsionIntegralEngine.hpp:48
enable_if_t< std::is_same< Z, GTOShell >::value, IntegralScalar > calculate(const CartesianGTO &left1, const CartesianGTO &left2, const CartesianGTO &right1, const CartesianGTO &right2)
Definition: PrimitiveCoulombRepulsionIntegralEngine.hpp:70
_Shell Shell
Definition: PrimitiveCoulombRepulsionIntegralEngine.hpp:45
Definition: BaseOneElectronIntegralBuffer.hpp:25
typename std::enable_if< B, T >::type enable_if_t
Definition: type_traits.hpp:37
decltype(std::declval< T >() *std::declval< U >()) product_t
Definition: aliases.hpp:35
std::complex< double > complex
Definition: complex.hpp:31
@ z
Definition: CartesianDirection.hpp:30
@ x
Definition: CartesianDirection.hpp:28
@ y
Definition: CartesianDirection.hpp:29
@ alpha
Definition: Spin.hpp:28
size_t value(const CartesianDirection direction) const
Definition: CartesianExponents.hpp:116