GQCP
Loading...
Searching...
No Matches
PrimitiveNuclearAttractionIntegralEngine.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
30namespace GQCP {
31
32
38template <typename _Shell>
41public:
42 // The type of shell that this integral engine is related to.
43 using Shell = _Shell;
44
45 // The type of primitive that underlies the type of shell.
46 using Primitive = typename Shell::Primitive;
47
48 // The scalar representation of a nuclear attraction integral.
50
51
52private:
53 // The nuclear attraction operator that this engine can calculate integrals over.
54 NuclearAttractionOperator nuclear_attraction_operator;
55
56
57public:
58 /*
59 * MARK: Constructors
60 */
61
66 nuclear_attraction_operator {nuclear_attraction_operator} {}
67
68
69 /*
70 * MARK: CartesianGTO integrals
71 */
72
81 template <typename Z = Shell>
83
84 // Prepare some variables.
85 const auto i = static_cast<int>(left.cartesianExponents().value(CartesianDirection::x));
86 const auto k = static_cast<int>(left.cartesianExponents().value(CartesianDirection::y));
87 const auto m = static_cast<int>(left.cartesianExponents().value(CartesianDirection::z));
88
89 const auto j = static_cast<int>(right.cartesianExponents().value(CartesianDirection::x));
90 const auto l = static_cast<int>(right.cartesianExponents().value(CartesianDirection::y));
91 const auto n = static_cast<int>(right.cartesianExponents().value(CartesianDirection::z));
92
93 const auto a = left.gaussianExponent();
94 const auto b = right.gaussianExponent();
95
96 const auto K_x = left.center()(CartesianDirection::x);
97 const auto K_y = left.center()(CartesianDirection::y);
98 const auto K_z = left.center()(CartesianDirection::z);
99
100 const auto L_x = right.center()(CartesianDirection::x);
101 const auto L_y = right.center()(CartesianDirection::y);
102 const auto L_z = right.center()(CartesianDirection::z);
103
104
105 // Prepare the McMurchie-Davidson coefficients.
106 const McMurchieDavidsonCoefficient E_x {K_x, a, L_x, b};
107 const McMurchieDavidsonCoefficient E_y {K_y, a, L_y, b};
108 const McMurchieDavidsonCoefficient E_z {K_z, a, L_z, b};
109
110 const double p = a + b;
111 const Vector<double, 3> P {E_x.centerOfMass(), E_y.centerOfMass(), E_z.centerOfMass()};
112
113
114 // Calculate the contributions from every nuclear center.
115 double total_integral {0.0};
116
117 const auto& nuclei = this->nuclear_attraction_operator.nuclearFramework().nucleiAsVector();
118 for (const auto& nucleus : nuclei) {
119 double integral {0.0};
120
121 const auto& C = nucleus.position();
122 const HermiteCoulombIntegral R {p, P, C};
123
124 for (int t = 0; t <= i + j; t++) {
125 for (int u = 0; u <= k + l; u++) {
126 for (int v = 0; v <= m + n; v++) {
127 // Add the contribution to the integral. The prefactor will be applied at the end.
128 integral += E_x(i, j, t) * E_y(k, l, u) * E_z(m, n, v) * R(0, t, u, v);
129 }
130 }
131 }
132 const auto charge = static_cast<double>(nucleus.charge());
133 total_integral += (-charge) * integral;
134 }
135
136 return 2 * boost::math::constants::pi<double>() / p * total_integral;
137 }
138
139
140 /*
141 * MARK: London CartesianGTO integrals
142 */
143
152 template <typename Z = Shell>
154
155 // Prepare some variables.
156 const auto i = static_cast<int>(left.cartesianGTO().cartesianExponents().value(CartesianDirection::x));
157 const auto k = static_cast<int>(left.cartesianGTO().cartesianExponents().value(CartesianDirection::y));
158 const auto m = static_cast<int>(left.cartesianGTO().cartesianExponents().value(CartesianDirection::z));
159
160 const auto j = static_cast<int>(right.cartesianGTO().cartesianExponents().value(CartesianDirection::x));
161 const auto l = static_cast<int>(right.cartesianGTO().cartesianExponents().value(CartesianDirection::y));
162 const auto n = static_cast<int>(right.cartesianGTO().cartesianExponents().value(CartesianDirection::z));
163
164 const auto a = left.cartesianGTO().gaussianExponent();
165 const auto b = right.cartesianGTO().gaussianExponent();
166
167 const auto K_x = left.cartesianGTO().center()(CartesianDirection::x);
168 const auto K_y = left.cartesianGTO().center()(CartesianDirection::y);
169 const auto K_z = left.cartesianGTO().center()(CartesianDirection::z);
170
171 const auto L_x = right.cartesianGTO().center()(CartesianDirection::x);
172 const auto L_y = right.cartesianGTO().center()(CartesianDirection::y);
173 const auto L_z = right.cartesianGTO().center()(CartesianDirection::z);
174
175 const Vector<double, 3> k1 = right.kVector() - left.kVector(); // The k-vector of the London overlap distribution.
176
177
178 // Prepare the McMurchie-Davidson coefficients.
179 const McMurchieDavidsonCoefficient E_x {K_x, a, L_x, b};
180 const McMurchieDavidsonCoefficient E_y {K_y, a, L_y, b};
181 const McMurchieDavidsonCoefficient E_z {K_z, a, L_z, b};
182
183 const double p = a + b;
184 const Vector<double, 3> P {E_x.centerOfMass(), E_y.centerOfMass(), E_z.centerOfMass()};
185
186
187 // Calculate the contributions from every nuclear center.
188 complex total_integral {};
189
190 const auto& nuclei = this->nuclear_attraction_operator.nuclearFramework().nucleiAsVector();
191 for (const auto& nucleus : nuclei) {
192 complex integral {};
193
194 const auto& C = nucleus.position();
195 const LondonHermiteCoulombIntegral R_k1 {k1, p, P, C};
196
197 for (int t = 0; t <= i + j; t++) {
198 for (int u = 0; u <= k + l; u++) {
199 for (int v = 0; v <= m + n; v++) {
200 // Add the contribution to the integral. The prefactor will be applied at the end.
201 integral += E_x(i, j, t) * E_y(k, l, u) * E_z(m, n, v) * R_k1(0, t, u, v);
202 }
203 }
204 }
205 const auto charge = static_cast<double>(nucleus.charge());
206 total_integral += (-charge) * integral;
207 }
208
209 return 2 * boost::math::constants::pi<double>() / p *
210 std::exp(-k1.squaredNorm() / (4 * p)) *
211 total_integral;
212 }
213};
214
215
216} // namespace GQCP
const NuclearFramework & nuclearFramework() const
Definition: BaseNuclearOperator.hpp:70
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: 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: LondonHermiteCoulombIntegral.hpp:31
Definition: Matrix.hpp:47
Definition: McMurchieDavidsonCoefficient.hpp:30
Definition: NuclearAttractionOperator.hpp:33
const std::vector< Nucleus > & nucleiAsVector() const
Definition: NuclearFramework.hpp:133
Definition: PrimitiveNuclearAttractionIntegralEngine.hpp:40
product_t< NuclearAttractionOperator::Scalar, typename Primitive::OutputType > IntegralScalar
Definition: PrimitiveNuclearAttractionIntegralEngine.hpp:49
enable_if_t< std::is_same< Z, GTOShell >::value, IntegralScalar > calculate(const CartesianGTO &left, const CartesianGTO &right)
Definition: PrimitiveNuclearAttractionIntegralEngine.hpp:82
_Shell Shell
Definition: PrimitiveNuclearAttractionIntegralEngine.hpp:43
typename Shell::Primitive Primitive
Definition: PrimitiveNuclearAttractionIntegralEngine.hpp:46
enable_if_t< std::is_same< Z, LondonGTOShell >::value, IntegralScalar > calculate(const LondonCartesianGTO &left, const LondonCartesianGTO &right)
Definition: PrimitiveNuclearAttractionIntegralEngine.hpp:153
PrimitiveNuclearAttractionIntegralEngine(const NuclearAttractionOperator &nuclear_attraction_operator)
Definition: PrimitiveNuclearAttractionIntegralEngine.hpp:65
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
size_t value(const CartesianDirection direction) const
Definition: CartesianExponents.hpp:116