JDFTx  1.2.0
Coulomb_internal.h
Go to the documentation of this file.
1 /*-------------------------------------------------------------------
2 Copyright 2012 Ravishankar Sundararaman
3 
4 This file is part of JDFTx.
5 
6 JDFTx is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10 
11 JDFTx is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with JDFTx. If not, see <http://www.gnu.org/licenses/>.
18 -------------------------------------------------------------------*/
19 
20 #ifndef JDFTX_CORE_COULOMB_INTERNAL_H
21 #define JDFTX_CORE_COULOMB_INTERNAL_H
22 
24 
25 #include <core/matrix3.h>
26 #include <core/Spline.h>
27 #include <gsl/gsl_integration.h>
28 
29 //Common citations for Coulomb truncation
30 #define wsTruncationPaper "R. Sundararaman and T.A. Arias, Phys. Rev. B 87, 165122 (2013)"
31 #define invariantTruncationPaper "S. Ismail-Beigi, Phys. Rev. B 73, 233103 (2006)"
32 #define expandedTruncationPaper "C.A. Rozzi et al., Phys. Rev. B 73, 205119 (2006)"
33 
34 //Ion-margin error message
35 #define ionMarginMessage "Expand unit cell, or if absolutely sure, reduce coulomb-truncation-ion-margin.\n"
36 
39 { __hostanddev__ double operator()(const vector3<int>& iG, const matrix3<>& GGT) const
40  { double Gsq = GGT.metric_length_squared(iG);
41  return Gsq ? (4*M_PI)/Gsq : 0.;
42  }
43 };
44 
47 { int iDir; double hlfL;
48  CoulombSlab_calc(int iDir, double hlfL) : iDir(iDir), hlfL(hlfL) {}
49  __hostanddev__ double operator()(const vector3<int>& iG, const matrix3<>& GGT) const
50  { double Gsq = GGT.metric_length_squared(iG);
51  double Gplane = Gsq - GGT(iDir,iDir) * iG[iDir]*iG[iDir]; //G along the non-truncated directions
52  Gplane = Gplane>0. ? sqrt(Gplane) : 0.; //safe sqrt to prevent NaN from roundoff errors
53  return (4*M_PI) * (Gsq ? (1. - exp(-Gplane*hlfL) * cos(M_PI*iG[iDir]))/Gsq : -0.5*hlfL*hlfL);
54  }
55 };
56 
59 { double Rc;
60  CoulombSpherical_calc(double Rc) : Rc(Rc) {}
61  __hostanddev__ double operator()(const vector3<int>& iG, const matrix3<>& GGT) const
62  { double Gsq = GGT.metric_length_squared(iG);
63  return Gsq ? (4*M_PI) * (1. - cos(Rc*sqrt(Gsq)))/Gsq : (2*M_PI)*Rc*Rc;
64  }
65 };
66 
67 #ifdef GPU_ENABLED
68 void coulombAnalytic_gpu(vector3<int> S, const matrix3<>& GGT, const CoulombPeriodic_calc& calc, complex* data);
69 void coulombAnalytic_gpu(vector3<int> S, const matrix3<>& GGT, const CoulombSlab_calc& calc, complex* data);
70 void coulombAnalytic_gpu(vector3<int> S, const matrix3<>& GGT, const CoulombSpherical_calc& calc, complex* data);
71 #endif
72 void coulombAnalytic(vector3<int> S, const matrix3<>& GGT, const CoulombPeriodic_calc& calc, complex* data);
73 void coulombAnalytic(vector3<int> S, const matrix3<>& GGT, const CoulombSlab_calc& calc, complex* data);
74 void coulombAnalytic(vector3<int> S, const matrix3<>& GGT, const CoulombSpherical_calc& calc, complex* data);
75 
77 __hostanddev__ double erf_by_x(double x)
78 { double xSq = x*x;
79  if(xSq<1e-6) return (1./sqrt(M_PI))*(2. - xSq*(2./3 + 0.2*xSq));
80  else return erf(x)/x;
81 }
82 
83 
84 
85 //--------------- Special function for cylinder/wire modes ------------
86 // (implemented in CoulombWire.cpp)
87 
89 struct Cbar
90 { Cbar();
91  ~Cbar();
92  double operator()(double k, double sigma, double rho, double rho0=1.);
93 private:
94  static const size_t maxIntervals = 1000;
95  gsl_integration_workspace* iWS;
96  static double integrandSmallRho(double t, void* params);
97  static double integrandLargeRho(double t, void* params);
98 };
99 
102 { Cbar_k_sigma(double k, double sigma, double rhoMax, double rho0=1.);
104  inline double value(double rho) const
105  { double f = QuinticSpline::value(coeff.data(), drhoInv * rho);
106  return isLog ? exp(f) : f;
107  }
109  inline double deriv(double rho) const
110  { double fp = QuinticSpline::deriv(coeff.data(), drhoInv * rho) * drhoInv;
111  return isLog ? fp * value(rho) : fp;
112  }
113 private:
114  double drhoInv; bool isLog;
115  std::vector<double> coeff;
116 };
117 
118 
119 //---------------------- Exchange Kernels --------------------
120 
121 //In each of the following functions, kSq is the square of the appropriate
122 //wave vector (includes reciprocal lattice vector and k-point difference),
123 //and will not be zero (the G=0 term is handled in the calling routine)
124 
126 __hostanddev__ double erfcTilde(double Gsq, double omegaSq)
127 { return (4*M_PI) * (omegaSq ? (1.-exp(-0.25*Gsq/omegaSq)) : 1.) / Gsq;
128 }
129 
130 
133 { __hostanddev__ double operator()(double kSq) const
134  { return (4*M_PI) / kSq;
135  }
136 };
137 
140 { double inv4omegaSq;
141  ExchangePeriodicScreened_calc(double omega) : inv4omegaSq(0.25/(omega*omega)) {}
142 
143  __hostanddev__ double operator()(double kSq) const
144  { return (4*M_PI) * (1.-exp(-inv4omegaSq*kSq)) / kSq;
145  }
146 };
147 
150 { double Rc;
151  ExchangeSpherical_calc(double Rc) : Rc(Rc) {}
152 
153  __hostanddev__ double operator()(double kSq) const
154  { return (4*M_PI) * (1. - cos(Rc * sqrt(kSq))) / kSq;
155  }
156 };
157 
160 { double* coeff;
161  double dGinv;
162  size_t nSamples;
163  ExchangeSphericalScreened_calc() : coeff(0) {}
164 
165  __hostanddev__ double operator()(double kSq) const
166  { double t = dGinv * sqrt(kSq);
167  if(t >= nSamples) return 0.;
168  else return QuinticSpline::value(coeff, t);
169  }
170 };
171 
174 { int iDir; double hlfL;
175  double* coeff; double dGinv; size_t nSamples, nCoeff; //quintic-spline coefficients for screened mode
176  ExchangeSlab_calc() : coeff(0) {}
177  __hostanddev__ double operator()(const vector3<int>& iG, const matrix3<>& GGT, const vector3<>& kDiff, double Vzero, double thresholdSq) const
178  { vector3<> g = iG + kDiff; //net G-vector in reciprocal lattice coordinates including k-point
179  double Gsq = GGT.metric_length_squared(g);
180  if(Gsq < thresholdSq)
181  return Vzero;
182  double Gplane = Gsq - GGT(iDir,iDir) * iG[iDir]*iG[iDir]; //G along the non-truncated directions (note kDiff[iDir]=0)
183  Gplane = Gplane>0. ? sqrt(Gplane) : 0.; //safe sqrt to prevent NaN from roundoff errors
184  double Vc = (4*M_PI) * (1. - exp(-Gplane*hlfL) * cos(M_PI*iG[iDir]))/Gsq; //Unscreened exchange (calculate analytically)
185  if(coeff)
186  { //Correct for Screened exchange using lookup table:
187  const double* coeffPlane = coeff + abs(iG[iDir]) * nCoeff; //coefficients for this plane
188  double t = dGinv * Gplane;
189  double prefac = iG[iDir] ? 1. : 1./Gplane;
190  if(t<nSamples) Vc += prefac * QuinticSpline::value(coeffPlane, t);
191  }
192  return Vc;
193  }
194 };
195 
196 
197 void exchangeAnalytic(vector3<int> S, const matrix3<>& GGT, const ExchangePeriodic_calc& calc, complex* data, const vector3<>& kDiff, double Vzero, double thresholdSq);
198 void exchangeAnalytic(vector3<int> S, const matrix3<>& GGT, const ExchangePeriodicScreened_calc& calc, complex* data, const vector3<>& kDiff, double Vzero, double thresholdSq);
199 void exchangeAnalytic(vector3<int> S, const matrix3<>& GGT, const ExchangeSpherical_calc& calc, complex* data, const vector3<>& kDiff, double Vzero, double thresholdSq);
200 void exchangeAnalytic(vector3<int> S, const matrix3<>& GGT, const ExchangeSphericalScreened_calc& calc, complex* data, const vector3<>& kDiff, double Vzero, double thresholdSq);
201 void exchangeAnalytic(vector3<int> S, const matrix3<>& GGT, const ExchangeSlab_calc& calc, complex* data, const vector3<>& kDiff, double Vzero, double thresholdSq);
202 #ifdef GPU_ENABLED
203 void exchangeAnalytic_gpu(vector3<int> S, const matrix3<>& GGT, const ExchangePeriodic_calc& calc, complex* data, const vector3<>& kDiff, double Vzero, double thresholdSq);
204 void exchangeAnalytic_gpu(vector3<int> S, const matrix3<>& GGT, const ExchangePeriodicScreened_calc& calc, complex* data, const vector3<>& kDiff, double Vzero, double thresholdSq);
205 void exchangeAnalytic_gpu(vector3<int> S, const matrix3<>& GGT, const ExchangeSpherical_calc& calc, complex* data, const vector3<>& kDiff, double Vzero, double thresholdSq);
206 void exchangeAnalytic_gpu(vector3<int> S, const matrix3<>& GGT, const ExchangeSphericalScreened_calc& calc, complex* data, const vector3<>& kDiff, double Vzero, double thresholdSq);
207 void exchangeAnalytic_gpu(vector3<int> S, const matrix3<>& GGT, const ExchangeSlab_calc& calc, complex* data, const vector3<>& kDiff, double Vzero, double thresholdSq);
208 #endif
209 
210 //Multiply a complexScalarFieldTilde's data by a RealKernel (real-symmetry reduced)
211 __hostanddev__ void multRealKernel_calc(size_t i, const vector3<int>& iG,
212  const vector3<int>& S, const double* kernel, complex* data)
213 { //Compute index on the real kernel:
214  vector3<int> iGreal = iG;
215  if(iGreal[2]<0) iGreal = -iGreal; //inversion symmetry in G-space for real-kernels
216  if(iGreal[1]<0) iGreal[1] += S[1];
217  if(iGreal[0]<0) iGreal[0] += S[0];
218  size_t iReal = iGreal[2] + size_t(1+S[2]/2) * (iGreal[1] + S[1]*iGreal[0]);
219  //Multiply:
220  data[i] *= kernel[iReal];
221 }
222 void multRealKernel(vector3<int> S, const double* kernel, complex* data);
223 #ifdef GPU_ENABLED
224 void multRealKernel_gpu(vector3<int> S, const double* kernel, complex* data);
225 #endif
226 
227 //Multiply a complexScalarFieldTilde's data by a kernel sampled with offset and rotation by rot
228 __hostanddev__ void multTransformedKernel_calc(size_t i, const vector3<int>& iG,
229  const vector3<int>& S, const double* kernel, complex* data, const vector3<int>& offset)
230 { vector3<int> iGkernel = (iG - offset); //Compute index on the real kernel
231  for(int k=0; k<3; k++) if(iGkernel[k]<0) iGkernel[k] += S[k]; //Reduce to [0,S-1) in each dimension
232  size_t iReal = iGkernel[2] + S[2]*size_t(iGkernel[1] + S[1]*iGkernel[0]); //net index into kernel
233  data[i] *= kernel[iReal];
234 }
235 void multTransformedKernel(vector3<int> S, const double* kernel, complex* data, const vector3<int>& offset);
236 #ifdef GPU_ENABLED
237 void multTransformedKernel_gpu(vector3<int> S, const double* kernel, complex* data, const vector3<int>& offset);
238 #endif
239 
240 #endif // JDFTX_CORE_COULOMB_INTERNAL_H
double inv4omegaSq
1/(4 omega^2)
Definition: Coulomb_internal.h:140
double dGinv
inverse of coefficient spacing
Definition: Coulomb_internal.h:161
ScalarField sqrt(const ScalarField &)
Elementwise square root (preserve input)
Erfc-screened Spherical-truncated exchange.
Definition: Coulomb_internal.h:159
Compute Cbar_k^sigma - the gaussian convolved cylindrical coulomb kernel - by numerical quadrature...
Definition: Coulomb_internal.h:89
Sphere-truncated coulomb interaction.
Definition: Coulomb_internal.h:58
__hostanddev__ double value(const double *coeff, double x)
Compute value of quintic spline. Warning: x is not range-checked.
__hostanddev__ double erfcTilde(double Gsq, double omegaSq)
Radial fourier transform of erfc(omega r)/r (not valid at G=0)
Definition: Coulomb_internal.h:126
double deriv(double rho) const
Get derivative:
Definition: Coulomb_internal.h:109
double value(double rho) const
Get value:
Definition: Coulomb_internal.h:104
Periodic exchange.
Definition: Coulomb_internal.h:132
Look-up table for Cbar_k^sigma(rho) for specific values of k and sigma.
Definition: Coulomb_internal.h:101
Slab-truncated exchange.
Definition: Coulomb_internal.h:173
__hostanddev__ double erf_by_x(double x)
Compute erf(x)/x (with x~0 handled properly)
Definition: Coulomb_internal.h:77
Periodic coulomb interaction (4 pi/G^2)
Definition: Coulomb_internal.h:38
ScalarField exp(const ScalarField &)
Elementwise exponential (preserve input)
double * coeff
quintic spline coefficients
Definition: Coulomb_internal.h:160
Erfc-screened Periodic exchange.
Definition: Coulomb_internal.h:139
Spherical-truncated exchange.
Definition: Coulomb_internal.h:149
__hostanddev__ double deriv(const double *coeff, double x)
Compute derivative (w.r.t x) of quintic spline. Warning: x is not range-checked.
Spline interpolation routines.
Complex number (need to define our own because we need operators for gpu code as well) ...
Definition: scalar.h:49
size_t nSamples
number of coefficients
Definition: Coulomb_internal.h:162
Slab-truncated coulomb interaction.
Definition: Coulomb_internal.h:46