QMCPACK
EwaldRef.cpp
Go to the documentation of this file.
1 //////////////////////////////////////////////////////////////////////////////////////
2 // This file is distributed under the University of Illinois/NCSA Open Source License.
3 // See LICENSE file in top directory for details.
4 //
5 // Copyright (c) 2019 QMCPACK developers.
6 //
7 // File developed by: Jaron T. Krogel, krogeljt@ornl.gov, Oak Ridge National Laboratory
8 //
9 // File created by: Jaron T. Krogel, krogeljt@ornl.gov, Oak Ridge National Laboratory
10 //////////////////////////////////////////////////////////////////////////////////////
11 
12 
13 #include "EwaldRef.h"
14 #include <cmath>
15 #include "Configuration.h"
16 #include "Utilities/TimerManager.h"
17 
18 namespace qmcplusplus
19 {
20 namespace ewaldref
21 {
22 
23 /// Functor for term within the real-space sum in Drummond 2008 formula 7
25 {
26 private:
27  /// The real-space cell axes
28  const RealMat a;
29  /// The constant \kappa in Drummond 2008 formula 7
30  const real_t rconst;
31 
32 public:
33  RspaceMadelungTerm(const RealMat& a_in, real_t rconst_in) : a(a_in), rconst(rconst_in) {}
34 
35  real_t operator()(const IntVec& i) const
36  {
37  RealVec Rv = dot(i, a);
38  real_t R = std::sqrt(dot(Rv, Rv));
39  real_t rm = std::erfc(rconst * R) / R;
40  return rm;
41  }
42 };
43 
44 
45 /// Functor for term within the k-space sum in Drummond 2008 formula 7
47 {
48 private:
49  /// The k-space cell axes
50  const RealMat b;
51  /// The constant 1/(4\kappa^2) in Drummond 2008 formula 7
52  const real_t kconst;
53  /// The constant 4\pi/\Omega in Drummond 2008 formula 7
54  const real_t kfactor;
55 
56 public:
57  KspaceMadelungTerm(const RealMat& b_in, real_t kconst_in, real_t kfactor_in)
58  : b(b_in), kconst(kconst_in), kfactor(kfactor_in)
59  {}
60 
61  real_t operator()(const IntVec& i) const
62  {
63  RealVec Kv = dot(i, b);
64  real_t K2 = dot(Kv, Kv);
65  real_t km = kfactor * std::exp(kconst * K2) / K2;
66  return km;
67  }
68 };
69 
70 
71 /// Functor for term within the real-space sum in Drummond 2008 formula 6
73 {
74 private:
75  /// The inter-particle separation vector
76  const RealVec r;
77  /// The real-space cell axes
78  const RealMat a;
79  /// The constant 1/(\sqrt{2}\kappa) in Drummond 2008 formula 6
80  const real_t rconst;
81 
82 public:
83  RspaceEwaldTerm(const RealVec& r_in, const RealMat& a_in, real_t rconst_in) : r(r_in), a(a_in), rconst(rconst_in) {}
84 
85  real_t operator()(const IntVec& i) const
86  {
87  RealVec Rv = dot(i, a);
88  for (int_t d : {0, 1, 2})
89  Rv[d] -= r[d];
90  real_t R = std::sqrt(dot(Rv, Rv));
91  real_t rm = std::erfc(rconst * R) / R;
92  return rm;
93  }
94 };
95 
96 
97 /// Functor for term within the k-space sum in Drummond 2008 formula 6
99 {
100 private:
101  /// The inter-particle separation vector
102  const RealVec r;
103  /// The k-space cell axes
104  const RealMat b;
105  /// The constant -\kappa^2/2 in Drummond 2008 formula 6
106  const real_t kconst;
107  /// The constant 4\pi/\Omega in Drummond 2008 formula 6
109 
110 public:
111  KspaceEwaldTerm(const RealVec& r_in, const RealMat& b_in, real_t kconst_in, real_t kfactor_in)
112  : r(r_in), b(b_in), kconst(kconst_in), kfactor(kfactor_in)
113  {}
114 
115  real_t operator()(const IntVec& i) const
116  {
117  RealVec Kv = dot(i, b);
118  real_t K2 = dot(Kv, Kv);
119  real_t Kr = dot(Kv, r);
120  real_t km = kfactor * std::exp(kconst * K2) * std::cos(Kr) / K2;
121  return km;
122  }
123 };
124 
125 
126 /** Perform a sum over successively larger cubic integer grids
127  * in DIM dimensional space for arbitrary functors.
128  *
129  * @param function: A functor accepting a point in the grid and
130  * returning the real-valued contribution to the sum from that
131  * point.
132  *
133  * @param zero: Include the origin in the sum (or not).
134  *
135  * @param tol: Tolerance for the sum. Summation ceases when the
136  * contribution to the sum from the outermost cubic shell of
137  * points is less than tol.
138  */
139 template<typename T>
140 real_t gridSum(T& function, bool zero = true, real_t tol = 1e-11)
141 {
142  real_t dv = std::numeric_limits<real_t>::max();
143  real_t dva = std::numeric_limits<real_t>::max();
144  real_t v = 0.0;
145  int_t im = 0;
146  int_t jm = 0;
147  int_t km = 0;
148  IntVec iv;
149  // Add the value at the origin, if requested.
150  if (zero)
151  {
152  iv = 0;
153  v += function(iv);
154  }
155  // Sum over cubic surface shells until the tolerance is reached.
156  while (std::abs(dva) > tol)
157  {
158  dva = 0.0;
159  dv = 0.0; // Surface shell contribution.
160  // Sum over new surface planes perpendicular to the x direction.
161  im += 1;
162  for (int_t i : {-im, im})
163  for (int_t j = -jm; j < jm + 1; ++j)
164  for (int_t k = -km; k < km + 1; ++k)
165  {
166  iv[0] = i;
167  iv[1] = j;
168  iv[2] = k;
169  real_t f = function(iv);
170  dv += f;
171  dva += std::abs(f);
172  }
173  // Sum over new surface planes perpendicular to the y direction.
174  jm += 1;
175  for (int_t j : {-jm, jm})
176  for (int_t k = -km; k < km + 1; ++k)
177  for (int_t i = -im; i < im + 1; ++i)
178  {
179  iv[0] = i;
180  iv[1] = j;
181  iv[2] = k;
182  real_t f = function(iv);
183  dv += f;
184  dva += std::abs(f);
185  }
186  // Sum over new surface planes perpendicular to the z direction.
187  km += 1;
188  for (int_t k : {-km, km})
189  for (int_t i = -im; i < im + 1; ++i)
190  for (int_t j = -jm; j < jm + 1; ++j)
191  {
192  iv[0] = i;
193  iv[1] = j;
194  iv[2] = k;
195  real_t f = function(iv);
196  dv += f;
197  dva += std::abs(f);
198  }
199  v += dv;
200  }
201 
202  return v;
203 }
204 
205 
206 /** Find the optimal kappa for Madelung sums
207  *
208  * The optimal kappa balances the number of points within a given
209  * isosurface of the Gaussians (or limiting Gaussians from erfc)
210  * in the real-space and k-space Madelung terms. The balancing
211  * condition is made under isotropic assumptions, as reflected
212  * by the use of a sphere equal in volume to the simulation cell
213  * to determine the radius.
214  *
215  * @param volume: Volume of the real space cell.
216  */
218 {
219  real_t radius = std::pow(3. * volume / (4 * M_PI), 1. / 3);
220  return std::sqrt(M_PI) / radius;
221 }
222 
223 
224 /** Compute the Madelung constant to a given tolerance
225  *
226  * Corresponds to the entirety of Drummond 2008 formula 7.
227  *
228  * @param a: Real-space cell axes.
229  *
230  * @param tol: Tolerance for the Madelung constant in Ha.
231  */
232 real_t madelungSum(const RealMat& a, real_t tol = 1e-10)
233 {
234  // Real-space cell volume
235  real_t volume = std::abs(det(a));
236  // k-space cell axes
237  RealMat b = 2 * M_PI * transpose(inverse(a));
238  // k-space cutoff (kappa)
239  real_t kconv = getKappaMadelung(volume);
240 
241  // Set constants for real-/k-space Madelung functors
242  real_t rconst = kconv;
243  real_t kconst = -1. / (4 * std::pow(kconv, 2));
244  real_t kfactor = 4 * M_PI / volume;
245 
246  // Create real-/k-space fuctors for terms within the sums in formula 7
247  RspaceMadelungTerm rfunc(a, rconst);
248  KspaceMadelungTerm kfunc(b, kconst, kfactor);
249 
250  // Compute the constant term
251  real_t cval = -M_PI / (std::pow(kconv, 2) * volume) - 2 * kconv / std::sqrt(M_PI);
252  // Compute the real-space sum (excludes zero)
253  real_t rval = gridSum(rfunc, false, tol);
254  // Compute the k-space sum (excludes zero)
255  real_t kval = gridSum(kfunc, false, tol);
256 
257  // Sum all contributions to get the Madelung constant
258  real_t ms = cval + rval + kval;
259 
260  return ms;
261 }
262 
263 
264 /** Find the optimal kappa for Ewald pair sums
265  *
266  * The optimal kappa balances the number of points within a given
267  * isosurface of the Gaussians (or limiting Gaussians from erfc)
268  * in the real-space and k-space Ewald pair terms. The balancing
269  * condition is made under isotropic assumptions, as reflected
270  * by the use of a sphere equal in volume to the simulation cell
271  * to determine the radius.
272  *
273  * @param volume: Volume of the real space cell.
274  */
276 {
277  real_t radius = std::pow(3. * volume / (4 * M_PI), 1. / 3);
278  return radius / std::sqrt(2 * M_PI);
279 }
280 
281 
282 /** Compute the Ewald interaction of a particle pair to a given tolerance
283  *
284  * Corresponds to the entirety of Drummond 2008 formula 6.
285  *
286  * @param r: Inter-particle separation vector.
287  *
288  * @param a: Real-space cell axes.
289  *
290  * @param tol: Tolerance for the Ewald pair interaction in Ha.
291  */
292 real_t ewaldSum(const RealVec& r, const RealMat& a, real_t tol = 1e-10)
293 {
294  // Real-space cell volume
295  real_t volume = std::abs(det(a));
296  // k-space cell axes
297  RealMat b = 2 * M_PI * transpose(inverse(a));
298  // k-space cutoff (kappa)
299  real_t kconv = getKappaEwald(volume);
300 
301  // Set constants for real-/k-space Ewald pair functors
302  real_t rconst = 1. / (std::sqrt(2.) * kconv);
303  real_t kconst = -std::pow(kconv, 2) / 2;
304  real_t kfactor = 4 * M_PI / volume;
305 
306  // Create real-/k-space fuctors for terms within the sums in formula 6
307  RspaceEwaldTerm rfunc(r, a, rconst);
308  KspaceEwaldTerm kfunc(r, b, kconst, kfactor);
309 
310  // Compute the constant term
311  real_t cval = -2 * M_PI * std::pow(kconv, 2) / volume;
312  // Compute the real-space sum (includes zero)
313  real_t rval = gridSum(rfunc, true, tol);
314  // Compute the k-space sum (excludes zero)
315  real_t kval = gridSum(kfunc, false, tol);
316 
317  // Sum all contributions to get the Ewald pair interaction
318  real_t es = cval + rval + kval;
319 
320  return es;
321 }
322 
323 
324 /** Compute the total Ewald potential energy for a collection of charges
325  *
326  * Corresponds to the entirety of Drummond 2008 formula 5, but for
327  * arbitrary charges.
328  *
329  * @param a: Real-space cell axes.
330  *
331  * @param R: List of particle coordinates.
332  *
333  * @param R: List of particle charges.
334  *
335  * @param tol: Tolerance for the total potential energy in Ha.
336  */
337 real_t ewaldEnergy(const RealMat& a, const PosArray& R, const ChargeArray& Q, real_t tol)
338 {
339  // Timer for EwaldRef
340  ScopedTimer totalEwaldTimer(createGlobalTimer("EwaldRef"));
341 
342  // Number of particles
343  const size_t N = R.size();
344 
345  // Total Ewald potential energy
346  real_t ve = 0.0;
347 
348  {
349  // Sum Madelung contributions
350  ScopedTimer totalMadelungTimer(createGlobalTimer("MadelungSum"));
351  // Maximum self-interaction charge product
352  real_t qqmax = 0.0;
353  for (size_t i = 0; i < N; ++i)
354  qqmax = std::max(std::abs(Q[i] * Q[i]), qqmax);
355 
356  // Compute the Madelung term (Drummond 2008 formula 7)
357  real_t vm = madelungSum(a, tol * 2. / qqmax);
358 
359  // Sum the Madelung self interaction for each particle
360  for (size_t i = 0; i < N; ++i)
361  ve += Q[i] * Q[i] * vm / 2;
362  }
363 
364  {
365  // Sum the interaction terms for all particle pairs
366  ScopedTimer EwaldSumTimer(createGlobalTimer("EwaldSum"));
367 
368 #pragma omp parallel for reduction(+ : ve)
369  for (size_t i = 1; i < N / 2 + 1; ++i)
370  {
371  for (size_t j = 0; j < i; ++j)
372  {
373  real_t qq = Q[i] * Q[j];
374  RealVec reduced = dot(R[i] - R[j], inverse(a));
375  for (size_t dim = 0; dim < DIM; dim++)
376  reduced[dim] -= std::floor(reduced[dim]);
377  RealVec rr = dot(reduced, a);
378  ve += qq * ewaldSum(rr, a, tol / qq);
379  }
380 
381  const size_t i_reverse = N - i;
382  if (i == i_reverse)
383  continue;
384 
385  for (size_t j = 0; j < i_reverse; ++j)
386  {
387  real_t qq = Q[i_reverse] * Q[j];
388  RealVec reduced = dot(R[i_reverse] - R[j], inverse(a));
389  for (size_t dim = 0; dim < DIM; dim++)
390  reduced[dim] -= std::floor(reduced[dim]);
391  RealVec rr = dot(reduced, a);
392  ve += qq * ewaldSum(rr, a, tol / qq);
393  }
394  }
395  }
396 
397  return ve;
398 }
399 
400 } // namespace ewaldref
401 } // namespace qmcplusplus
Functor for term within the real-space sum in Drummond 2008 formula 7.
Definition: EwaldRef.cpp:24
Fixed-size array.
Definition: OhmmsTinyMeta.h:30
helper functions for EinsplineSetBuilder
Definition: Configuration.h:43
timer_manager class.
Tensor< T, D >::Type_t det(const Tensor< T, D > &a)
Definition: TensorOps.h:838
Functor for term within the real-space sum in Drummond 2008 formula 6.
Definition: EwaldRef.cpp:72
MakeReturn< UnaryNode< FnFabs, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t abs(const Vector< T1, C1 > &l)
RspaceMadelungTerm(const RealMat &a_in, real_t rconst_in)
Definition: EwaldRef.cpp:33
std::vector< real_t > ChargeArray
Type for lists of particle charges.
Definition: EwaldRef.h:54
Computes Ewald sums of the potential energy to a given tolerance for arbitrary collections of charges...
real_t operator()(const IntVec &i) const
Definition: EwaldRef.cpp:61
real_t ewaldEnergy(const RealMat &a, const PosArray &R, const ChargeArray &Q, real_t tol)
Compute the total Ewald potential energy for a collection of charges.
Definition: EwaldRef.cpp:337
real_t gridSum(T &function, bool zero=true, real_t tol=1e-11)
Perform a sum over successively larger cubic integer grids in DIM dimensional space for arbitrary fun...
Definition: EwaldRef.cpp:140
real_t operator()(const IntVec &i) const
Definition: EwaldRef.cpp:35
int int_t
Type for integers.
Definition: EwaldRef.h:42
std::vector< RealVec > PosArray
Type for lists of particle positions.
Definition: EwaldRef.h:52
const RealMat a
The real-space cell axes.
Definition: EwaldRef.cpp:78
RspaceEwaldTerm(const RealVec &r_in, const RealMat &a_in, real_t rconst_in)
Definition: EwaldRef.cpp:83
KspaceMadelungTerm(const RealMat &b_in, real_t kconst_in, real_t kfactor_in)
Definition: EwaldRef.cpp:57
MakeReturn< BinaryNode< FnPow, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t, typename CreateLeaf< Vector< T2, C2 > >::Leaf_t > >::Expression_t pow(const Vector< T1, C1 > &l, const Vector< T2, C2 > &r)
const RealMat a
The real-space cell axes.
Definition: EwaldRef.cpp:28
real_t getKappaMadelung(real_t volume)
Find the optimal kappa for Madelung sums.
Definition: EwaldRef.cpp:217
Functor for term within the k-space sum in Drummond 2008 formula 7.
Definition: EwaldRef.cpp:46
MakeReturn< UnaryNode< FnCos, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t cos(const Vector< T1, C1 > &l)
const real_t rconst
The constant in Drummond 2008 formula 7.
Definition: EwaldRef.cpp:30
Tensor<T,D> class for D by D tensor.
Definition: OhmmsTinyMeta.h:32
NewTimer & createGlobalTimer(const std::string &myname, timer_levels mylevel)
const real_t kfactor
The constant 4/ in Drummond 2008 formula 7.
Definition: EwaldRef.cpp:54
const RealVec r
The inter-particle separation vector.
Definition: EwaldRef.cpp:76
real_t getKappaEwald(real_t volume)
Find the optimal kappa for Ewald pair sums.
Definition: EwaldRef.cpp:275
Functor for term within the k-space sum in Drummond 2008 formula 6.
Definition: EwaldRef.cpp:98
const RealMat b
The k-space cell axes.
Definition: EwaldRef.cpp:104
real_t ewaldSum(const RealVec &r, const RealMat &a, real_t tol=1e-10)
Compute the Ewald interaction of a particle pair to a given tolerance.
Definition: EwaldRef.cpp:292
const RealMat b
The k-space cell axes.
Definition: EwaldRef.cpp:50
MakeReturn< UnaryNode< FnExp, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t exp(const Vector< T1, C1 > &l)
real_t operator()(const IntVec &i) const
Definition: EwaldRef.cpp:115
AntiSymTensor< T, D > transpose(const AntiSymTensor< T, D > &rhs)
const real_t kconst
The constant -^2/2 in Drummond 2008 formula 6.
Definition: EwaldRef.cpp:106
const real_t rconst
The constant 1/({2}) in Drummond 2008 formula 6.
Definition: EwaldRef.cpp:80
KspaceEwaldTerm(const RealVec &r_in, const RealMat &b_in, real_t kconst_in, real_t kfactor_in)
Definition: EwaldRef.cpp:111
MakeReturn< UnaryNode< FnSqrt, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t sqrt(const Vector< T1, C1 > &l)
Tensor< T, D > inverse(const Tensor< T, D > &a)
Definition: TensorOps.h:879
Tensor< typename BinaryReturn< T1, T2, OpMultiply >::Type_t, D > dot(const AntiSymTensor< T1, D > &lhs, const AntiSymTensor< T2, D > &rhs)
double real_t
Type for floating point numbers.
Definition: EwaldRef.h:44
real_t operator()(const IntVec &i) const
Definition: EwaldRef.cpp:85
const RealVec r
The inter-particle separation vector.
Definition: EwaldRef.cpp:102
real_t madelungSum(const RealMat &a, real_t tol=1e-10)
Compute the Madelung constant to a given tolerance.
Definition: EwaldRef.cpp:232
const real_t kfactor
The constant 4/ in Drummond 2008 formula 6.
Definition: EwaldRef.cpp:108
const real_t kconst
The constant 1/(4^2) in Drummond 2008 formula 7.
Definition: EwaldRef.cpp:52
MakeReturn< UnaryNode< FnFloor, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t floor(const Vector< T1, C1 > &l)