GQCP
Loading...
Searching...
No Matches
PrimitiveElectronicDipoleIntegralEngine.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
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 an overlap integral.
52
53
54private:
55 // The electronic dipole operator over which integrals should be calculated.
56 ElectronicDipoleOperator dipole_operator;
57
58
59public:
60 /*
61 * MARK: Constructors
62 */
63
69 dipole_operator {dipole_operator},
71
72
73 /*
74 * MARK: CartesianGTO integrals
75 */
76
85 template <typename Z = Shell>
87
88 // Prepare some variables.
89 const auto i = static_cast<int>(left.cartesianExponents().value(CartesianDirection::x));
90 const auto k = static_cast<int>(left.cartesianExponents().value(CartesianDirection::y));
91 const auto m = static_cast<int>(left.cartesianExponents().value(CartesianDirection::z));
92
93 const auto j = static_cast<int>(right.cartesianExponents().value(CartesianDirection::x));
94 const auto l = static_cast<int>(right.cartesianExponents().value(CartesianDirection::y));
95 const auto n = static_cast<int>(right.cartesianExponents().value(CartesianDirection::z));
96
97 const auto a = left.gaussianExponent();
98 const auto b = right.gaussianExponent();
99
100 const auto K_x = left.center()(CartesianDirection::x);
101 const auto K_y = left.center()(CartesianDirection::y);
102 const auto K_z = left.center()(CartesianDirection::z);
103
104 const auto L_x = right.center()(CartesianDirection::x);
105 const auto L_y = right.center()(CartesianDirection::y);
106 const auto L_z = right.center()(CartesianDirection::z);
107
109
110
111 // For the current component, the integral can be calculated as a product of three contributions.
112 switch (this->component) {
114 return this->calculate1D(a, K_x, i, b, L_x, j) * S.calculate1D(a, K_y, k, b, L_y, l) * S.calculate1D(a, K_z, m, b, L_z, n);
115 break;
116 }
117
119 return S.calculate1D(a, K_x, i, b, L_x, j) * this->calculate1D(a, K_y, k, b, L_y, l) * S.calculate1D(a, K_z, m, b, L_z, n);
120 break;
121 }
122
124 return S.calculate1D(a, K_x, i, b, L_x, j) * S.calculate1D(a, K_y, k, b, L_y, l) * this->calculate1D(a, K_z, m, b, L_z, n);
125 break;
126 }
127 }
128 }
129
142 template <typename Z = Shell>
143 enable_if_t<std::is_same<Z, GTOShell>::value, IntegralScalar> calculate1D(const double a, const double K, const int i, const double b, const double L, const int j) {
144
145 // Prepare some variables.
146 const McMurchieDavidsonCoefficient E {K, a, L, b};
147 const auto P = E.centerOfMass();
148 const auto p = a + b;
149
150 const auto X_PC = P - this->dipole_operator.reference()(this->component); // The distance between P and the origin of the dipole operator.
151
152
153 // Calculate the dipole integral over the current component. The minus sign comes from the charge of the electron.
154 return -std::pow(boost::math::constants::pi<double>() / p, 0.5) * (E(i, j, 1) + X_PC * E(i, j, 0));
155 }
156
157
158 /*
159 * MARK: London CartesianGTO integrals
160 */
161
170 template <typename Z = Shell>
172
173 // Prepare some variables.
174 const auto i = static_cast<int>(left.cartesianGTO().cartesianExponents().value(CartesianDirection::x));
175 const auto k = static_cast<int>(left.cartesianGTO().cartesianExponents().value(CartesianDirection::y));
176 const auto m = static_cast<int>(left.cartesianGTO().cartesianExponents().value(CartesianDirection::z));
177
178 const auto j = static_cast<int>(right.cartesianGTO().cartesianExponents().value(CartesianDirection::x));
179 const auto l = static_cast<int>(right.cartesianGTO().cartesianExponents().value(CartesianDirection::y));
180 const auto n = static_cast<int>(right.cartesianGTO().cartesianExponents().value(CartesianDirection::z));
181
182 const auto a = left.cartesianGTO().gaussianExponent();
183 const auto b = right.cartesianGTO().gaussianExponent();
184
185 const auto K_x = left.cartesianGTO().center()(CartesianDirection::x);
186 const auto K_y = left.cartesianGTO().center()(CartesianDirection::y);
187 const auto K_z = left.cartesianGTO().center()(CartesianDirection::z);
188
189 const auto L_x = right.cartesianGTO().center()(CartesianDirection::x);
190 const auto L_y = right.cartesianGTO().center()(CartesianDirection::y);
191 const auto L_z = right.cartesianGTO().center()(CartesianDirection::z);
192
193 const Vector<double, 3> k1 = right.kVector() - left.kVector(); // The k-vector of the London overlap distribution.
194
195 const auto k1_x = k1(CartesianDirection::x);
196 const auto k1_y = k1(CartesianDirection::y);
197 const auto k1_z = k1(CartesianDirection::z);
198
200
201
202 // For the current component, the integral can be calculated as a product of three contributions.
203 switch (this->component) {
205 return this->calculate1D(k1_x, a, K_x, i, b, L_x, j) * S.calculate1D(k1_y, a, K_y, k, b, L_y, l) * S.calculate1D(k1_z, a, K_z, m, b, L_z, n);
206 break;
207 }
208
210 return S.calculate1D(k1_x, a, K_x, i, b, L_x, j) * this->calculate1D(k1_y, a, K_y, k, b, L_y, l) * S.calculate1D(k1_z, a, K_z, m, b, L_z, n);
211 break;
212 }
213
215 return S.calculate1D(k1_x, a, K_x, i, b, L_x, j) * S.calculate1D(k1_y, a, K_y, k, b, L_y, l) * this->calculate1D(k1_z, a, K_z, m, b, L_z, n);
216 break;
217 }
218 }
219 }
220
221
235 template <typename Z = Shell>
236 enable_if_t<std::is_same<Z, LondonGTOShell>::value, IntegralScalar> calculate1D(const complex k1, const double a, const double K, const int i, const double b, const double L, const int j) {
237
238 // Prepare some variables.
239 const auto X_KC = K - this->dipole_operator.reference()(this->component); // The distance between K and the origin of the dipole operator.
240
241
242 // The 1-D electronic dipole integral can be calculated completely from overlap integrals. The sign factor is included to account for the sign of the electron.
244 return (-1.0) * (S.calculate1D(k1, a, K, i + 1, b, L, j) +
245 X_KC * S.calculate1D(k1, a, K, i, b, L, j));
246 }
247};
248
249
250} // namespace GQCP
const Vector< double, 3 > & reference() const
Definition: BaseReferenceDependentOperator.hpp:66
Definition: BaseVectorPrimitiveIntegralEngine.hpp:32
CartesianDirection component
Definition: BaseVectorPrimitiveIntegralEngine.hpp:36
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: ElectronicDipoleOperator.hpp:33
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
double centerOfMass() const
Definition: McMurchieDavidsonCoefficient.cpp:87
Definition: PrimitiveElectronicDipoleIntegralEngine.hpp:42
enable_if_t< std::is_same< Z, GTOShell >::value, IntegralScalar > calculate(const CartesianGTO &left, const CartesianGTO &right)
Definition: PrimitiveElectronicDipoleIntegralEngine.hpp:86
enable_if_t< std::is_same< Z, LondonGTOShell >::value, IntegralScalar > calculate1D(const complex k1, const double a, const double K, const int i, const double b, const double L, const int j)
Definition: PrimitiveElectronicDipoleIntegralEngine.hpp:236
_Shell Shell
Definition: PrimitiveElectronicDipoleIntegralEngine.hpp:45
product_t< ElectronicDipoleOperator::Scalar, typename Primitive::OutputType > IntegralScalar
Definition: PrimitiveElectronicDipoleIntegralEngine.hpp:51
PrimitiveElectronicDipoleIntegralEngine(const ElectronicDipoleOperator &dipole_operator, const CartesianDirection component=CartesianDirection::x)
Definition: PrimitiveElectronicDipoleIntegralEngine.hpp:68
enable_if_t< std::is_same< Z, GTOShell >::value, IntegralScalar > calculate1D(const double a, const double K, const int i, const double b, const double L, const int j)
Definition: PrimitiveElectronicDipoleIntegralEngine.hpp:143
typename Shell::Primitive Primitive
Definition: PrimitiveElectronicDipoleIntegralEngine.hpp:48
enable_if_t< std::is_same< Z, LondonGTOShell >::value, IntegralScalar > calculate(const LondonCartesianGTO &left, const LondonCartesianGTO &right)
Definition: PrimitiveElectronicDipoleIntegralEngine.hpp:171
Definition: PrimitiveOverlapIntegralEngine.hpp:43
enable_if_t< std::is_same< Z, GTOShell >::value, IntegralScalar > calculate1D(const double a, const double K, const int i, const double b, const double L, const int j)
Definition: PrimitiveOverlapIntegralEngine.hpp:97
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
CartesianDirection
Definition: CartesianDirection.hpp:27
@ 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