JDFTx  1.2.0
ExCorr_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_ELECTRONIC_EXCORR_INTERNAL_H
21 #define JDFTX_ELECTRONIC_EXCORR_INTERNAL_H
22 
25 
26 #include <electronic/operators_internal.h>
27 
28 static const double nCutoff = 1e-16;
29 
33 #define SwitchTemplate_spin(SwitchTemplate_functional,variant,nCount, fTemplate,argList) \
34  switch(nCount) \
35  { case 1: { SwitchTemplate_functional(variant,1, fTemplate,argList) break; } \
36  case 2: { SwitchTemplate_functional(variant,2, fTemplate,argList) break; } \
37  default: break; \
38  }
39 
40 
43 {
44 protected:
45  double scaleFac;
46 public:
47  Functional(double scaleFac=1.0) : scaleFac(scaleFac) {}
48  virtual bool needsSigma() const=0;
49  virtual bool needsLap() const=0;
50  virtual bool needsTau() const=0;
51  virtual bool hasExchange() const=0;
52  virtual bool hasCorrelation() const=0;
53  virtual bool hasKinetic() const=0;
54  virtual bool hasEnergy() const=0;
55 
69  virtual void evaluate(int N, std::vector<const double*> n, std::vector<const double*> sigma,
70  std::vector<const double*> lap, std::vector<const double*> tau,
71  double* E, std::vector<double*> E_n, std::vector<double*> E_sigma,
72  std::vector<double*> E_lap, std::vector<double*> E_tau) const=0;
73 
75  void evaluateSub(int iStart, int iStop,
76  std::vector<const double*> n, std::vector<const double*> sigma,
77  std::vector<const double*> lap, std::vector<const double*> tau,
78  double* E, std::vector<double*> E_n, std::vector<double*> E_sigma,
79  std::vector<double*> E_lap, std::vector<double*> E_tau) const;
80 };
81 
83 __hostanddev__ void loadSpinVector(array<const double*,4> x, int i, double& x0, vector3<>& xVec)
84 { x0 = x[0][i] + x[1][i];
85  xVec = vector3<>( 2*x[2][i], -2*x[3][i], x[0][i]-x[1][i] );
86 }
87 __hostanddev__ void accumSpinVectorGrad(const double& E_x0, const vector3<>& E_xVec, array<double*,4> E_x, int i)
88 { E_x[0][i] += (E_x0 + E_xVec[2]);
89  E_x[1][i] += (E_x0 - E_xVec[2]);
90  E_x[2][i] += 2 * E_xVec[0];
91  E_x[3][i] -= 2 * E_xVec[1];
92 }
93 
96 { //Compute magnetization:
97  double n0; vector3<> mVec; loadSpinVector(n,i, n0,mVec); //total density and magnetization vector
98  double mNormFac = 1./sqrt(mVec.length_squared() + nCutoff); //regularized normalization factor
99  vector3<> mHat = mVec * mNormFac; //regularized unit vector along magentization
100  //Get the scalar and vector components of x:
101  double x0; vector3<> xVec; loadSpinVector(x,i, x0,xVec);
102  //Store the relevant projection of x:
103  double xdotmHat = dot(xVec,mHat);
104  xDiag[0][i] = 0.5*(x0 + xdotmHat);
105  xDiag[1][i] = 0.5*(x0 - xdotmHat);
106 }
107 
110 { //Compute magnetization:
111  double n0; vector3<> mVec; loadSpinVector(n,i, n0,mVec); //total density and magnetization vector
112  double mNormFac = 1./sqrt(mVec.length_squared() + nCutoff); //regularized normalization factor
113  vector3<> mHat = mVec * mNormFac; //regularized unit vector along magentization
114  //Get the scalar and vector components of x:
115  double x0; vector3<> xVec; loadSpinVector(x,i, x0,xVec);
116  //Propagate E_xDiag to E_x0, E_xVec and E_mVec:
117  double E_x0 = 0.5*(E_xDiag[0][i] + E_xDiag[1][i]);
118  double E_xdotmHat = 0.5*(E_xDiag[0][i] - E_xDiag[1][i]);
119  vector3<> E_xVec = E_xdotmHat * mHat;
120  vector3<> E_mVec = (E_xdotmHat * mNormFac) * (xVec - dot(xVec,mHat)*mHat);
121  //Accumulate results in output arrays:
122  accumSpinVectorGrad( 0. ,E_mVec, E_n,i);
123  accumSpinVectorGrad(E_x0,E_xVec, E_x,i);
124 }
125 
126 
128 __hostanddev__ double spinInterpolation(double zeta, double& f_zeta)
129 { const double scale = 1./(pow(2.,4./3) - 2);
130  double zetaPlusCbrt = pow(1+zeta, 1./3);
131  double zetaMinusCbrt = pow(1-zeta, 1./3);
132  f_zeta = scale*(zetaPlusCbrt - zetaMinusCbrt)*(4./3);
133  return scale*((1+zeta)*zetaPlusCbrt + (1-zeta)*zetaMinusCbrt - 2.);
134 }
135 
137 template<typename Para, typename Ferro> __hostanddev__
138 double spinInterpolate(double rs, double zeta, double& e_rs, double& e_zeta, const Para& para, const Ferro& ferro)
139 { double ePara_rs, ePara = para(rs, ePara_rs);
140  if(!zeta)
141  { //Return paramagnetic result:
142  e_rs = ePara_rs;
143  e_zeta = 0.;
144  return ePara;
145  }
146  else //Mix in ferromagnetic result:
147  { double eFerro_rs, eFerro = ferro(rs, eFerro_rs);
148  double f_zeta, f = spinInterpolation(zeta, f_zeta); //spin interpolation function
149  e_rs = ePara_rs + f*(eFerro_rs - ePara_rs);
150  e_zeta = f_zeta*(eFerro - ePara);
151  return ePara + f*(eFerro - ePara);
152  }
153 }
154 
158 template<typename Para, typename Ferro, typename Stiff> __hostanddev__
159 double spinInterpolate(double rs, double zeta, double& e_rs, double& e_zeta,
160  const Para& para, const Ferro& ferro, const Stiff& stiff,
161  const double fDblPrime0 = 4./(9*(pow(2., 1./3)-1)))
162 {
163  double ePara_rs, ePara = para(rs, ePara_rs); //Paramagentic
164  if(!zeta) //return paramagentic result
165  { e_rs = ePara_rs;
166  e_zeta = 0.;
167  return ePara;
168  }
169  else //Mix in ferromagnetic and zeta-derivative results:
170  { double eFerro_rs, eFerro = ferro(rs, eFerro_rs); //Ferromagnetic
171  double eStiff_rs, eStiff = stiff(rs, eStiff_rs); //Spin-derivative
172  //Compute mix factors:
173  double f_zeta, f = spinInterpolation(zeta, f_zeta); //spin interpolation function
174  double zeta2=zeta*zeta, zeta3=zeta2*zeta, zeta4=zeta2*zeta2; //powers of zeta
175  const double scale = -1./fDblPrime0;
176  double w1 = zeta4*f, w1_zeta = 4*zeta3*f + zeta4*f_zeta;
177  double w2 = scale*((1-zeta4)*f), w2_zeta = scale*(-4*zeta3*f + (1-zeta4)*f_zeta);
178  //Mix:
179  e_rs = ePara_rs + w1*(eFerro_rs-ePara_rs) + w2*eStiff_rs;
180  e_zeta = w1_zeta*(eFerro-ePara) + w2_zeta*eStiff;
181  return ePara + w1*(eFerro-ePara) + w2*eStiff;
182  }
183 }
184 
185 #endif // JDFTX_ELECTRONIC_EXCORR_INTERNAL_H
186 
virtual bool hasExchange() const =0
whether this functional includes exchange
virtual bool needsTau() const =0
return true if orbital kinetic energy density is used (MGGA)
ScalarField pow(const ScalarField &, double alpha)
Elementwise power (preserve input)
void evaluateSub(int iStart, int iStop, std::vector< const double * > n, std::vector< const double * > sigma, std::vector< const double * > lap, std::vector< const double * > tau, double *E, std::vector< double * > E_n, std::vector< double * > E_sigma, std::vector< double * > E_lap, std::vector< double * > E_tau) const
Call evaluate for a subset of data points:
ScalarField sqrt(const ScalarField &)
Elementwise square root (preserve input)
complex dot(const Tptr &X, const Tptr &Y)
Definition: Operators.h:196
double scaleFac
scale factor (to support mixing for hybrid functionals)
Definition: ExCorr_internal.h:45
virtual bool hasEnergy() const =0
whether total energy is meaningful for this functional
virtual bool hasKinetic() const =0
whether this functional includes kinetic energy
__hostanddev__ double spinInterpolation(double zeta, double &f_zeta)
LDA spin interpolation function f(zeta) and its derivative.
Definition: ExCorr_internal.h:128
virtual bool needsLap() const =0
return true if laplacian of density is used (MGGA)
__hostanddev__ void spinDiagonalizeGrad_calc(int i, array< const double *, 4 > n, array< const double *, 4 > x, array< const double *, 2 > E_xDiag, array< double *, 4 > E_n, array< double *, 4 > E_x)
Propagate gradients corresponding to spinDiagonalize_calc(), from E_xDiag and accumulate to E_n and E...
Definition: ExCorr_internal.h:109
Definition: operators_internal.h:37
__hostanddev__ void spinDiagonalize_calc(int i, array< const double *, 4 > n, array< const double *, 4 > x, array< double *, 2 > xDiag)
Transform spin-density-matrix-like quantity x into the basis where spin-density-matrix n is diagonal...
Definition: ExCorr_internal.h:95
Abstract base class for functionals.
Definition: ExCorr_internal.h:42
__hostanddev__ double spinInterpolate(double rs, double zeta, double &e_rs, double &e_zeta, const Para &para, const Ferro &ferro)
Spin-interpolate an LDA functional given its paramagnetic and ferromagnetic functors.
Definition: ExCorr_internal.h:138
virtual bool hasCorrelation() const =0
whether this functional includes correlation
virtual bool needsSigma() const =0
return true if density gradients are used
__hostanddev__ void loadSpinVector(array< const double *, 4 > x, int i, double &x0, vector3<> &xVec)
Utility function for converting to/from spin-density matrices to scalar+vector combinations (via Paul...
Definition: ExCorr_internal.h:83
virtual void evaluate(int N, std::vector< const double * > n, std::vector< const double * > sigma, std::vector< const double * > lap, std::vector< const double * > tau, double *E, std::vector< double * > E_n, std::vector< double * > E_sigma, std::vector< double * > E_lap, std::vector< double * > E_tau) const =0