//////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2008 The Regents of the University of California // // This file is part of Qbox // // Qbox is distributed under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 2 of // the License, or (at your option) any later version. // See the file COPYING in the root directory of this distribution // or . // //////////////////////////////////////////////////////////////////////////////// // // LDAFunctional.C // // LDA Exchange-correlation energy and potential // Ceperley & Alder, parametrized by Perdew and Zunger // //////////////////////////////////////////////////////////////////////////////// // $Id: LDAFunctional.C,v 1.7 2008-09-08 15:56:18 fgygi Exp $ #include #include #include #include "LDAFunctional.h" void LDAFunctional::setxc(void) { if ( _np == 0 ) return; if ( _nspin == 1 ) { assert(rho != 0); assert(exc != 0); assert(vxc1 != 0); #pragma omp parallel for for ( int ir = 0; ir < _np; ir++ ) { xc_unpolarized(rho[ir],exc[ir],vxc1[ir]); } } else { // spin polarized assert(rho_up != 0); assert(rho_dn != 0); assert(exc != 0); assert(vxc1_up != 0); assert(vxc1_dn != 0); const double fz_prefac = 1.0 / ( cbrt(2.0)*2.0 - 2.0 ); const double dfz_prefac = (4.0/3.0) * fz_prefac; #pragma omp parallel for for ( int ir = 0; ir < _np; ir++ ) { double excir = 0.0; double v_up = 0.0; double v_dn = 0.0; double roe_up = rho_up[ir]; double roe_dn = rho_dn[ir]; double roe = roe_up + roe_dn; if ( roe > 0.0 ) { double zeta = ( roe_up - roe_dn ) / roe; double zp1 = 1.0 + zeta; double zm1 = 1.0 - zeta; double zp1_13 = cbrt(zp1); double zm1_13 = cbrt(zm1); double fz = fz_prefac * ( zp1_13 * zp1 + zm1_13 * zm1 - 2.0 ); double dfz = dfz_prefac * ( zp1_13 - zm1_13 ); double xc_u, xc_p, v_u, v_p; xc_unpolarized(roe,xc_u,v_u); xc_polarized(roe,xc_p,v_p); double xc_pu = xc_p - xc_u; excir = xc_u + fz * xc_pu; double v = v_u + fz * ( v_p - v_u ); v_up = v + xc_pu * ( 1.0 - zeta ) * dfz; v_dn = v + xc_pu * ( -1.0 - zeta ) * dfz; } vxc1_up[ir] = v_up; vxc1_dn[ir] = v_dn; exc[ir] = excir; } } } void LDAFunctional::xc_unpolarized(const double rh, double &ee, double &vv) { // compute LDA xc energy and potential, unpolarized // const double third=1.0/3.0; // c1 is (3.D0/(4.D0*pi))**third const double c1 = 0.6203504908994001; // alpha = (4/(9*pi))**third = 0.521061761198 // const double alpha = 0.521061761198; // c2 = -(3/(4*pi)) / alpha = -0.458165293283 // const double c2 = -0.458165293283; // c3 = (4/3) * c2 = -0.610887057711 const double c3 = -0.610887057711; const double A = 0.0311; const double B = -0.048; const double b1 = 1.0529; const double b2 = 0.3334; const double G = -0.1423; // C from the PZ paper: const double C = 0.0020; // D from the PZ paper: const double D = -0.0116; // C and D by matching Ec and Vc at rs=1 const double D = G / ( 1.0 + b1 + b2 ) - B; const double C = -A - D - G * ( (b1/2.0 + b2) / ((1.0+b1+b2)*(1.0+b1+b2))); ee = 0.0; vv = 0.0; if ( rh > 0.0 ) { double ro13 = cbrt(rh); double rs = c1 / ro13; double ex=0.0,vx=0.0,ec=0.0,vc=0.0; // Next line : exchange part in Hartree units vx = c3 / rs; ex = 0.75 * vx; // Next lines : Ceperley & Alder correlation (Zunger & Perdew) if ( rs < 1.0 ) { double logrs = log(rs); ec = A * logrs + B + C * rs * logrs + D * rs; vc = A * logrs + ( B - A / 3.0 ) + (2.0/3.0) * C * rs * logrs + ( ( 2.0 * D - C ) / 3.0 ) * rs; } else { double sqrtrs = sqrt(rs); double den = 1.0 + b1 * sqrtrs + b2 * rs; ec = G / den; vc = ec * ( 1.0 + (7.0/6.0) * b1 * sqrtrs + (4.0/3.0) * b2 * rs ) / den; } ee = ex + ec; vv = vx + vc; } } void LDAFunctional::xc_polarized(const double rh, double &ee, double &vv) { // compute LDA polarized XC energy and potential // const double third=1.0/3.0; // c1 is (3.D0/(4.D0*pi))**third const double c1 = 0.6203504908994001; // alpha = (4/(9*pi))**third = 0.521061761198 // const double alpha = 0.521061761198; // c2 = -(3/(4*pi)) / alpha = -0.458165293283 // const double c2 = -0.458165293283; // c3 = (4/3) * c2 = -0.610887057711 // const double c3 = -0.610887057711; // c4 = 2**third * c3 const double c4 = -0.769669463118; const double A = 0.01555; const double B = -0.0269; const double b1 = 1.3981; const double b2 = 0.2611; const double G = -0.0843; // C from PZ paper: const double C = 0.0007; // D from PZ paper: const double D = -0.0048; // C and D by matching Ec and Vc at rs=1 const double D = G / ( 1.0 + b1 + b2 ) - B; const double C = -A - D - G * ( (b1/2.0 + b2) / ((1.0+b1+b2)*(1.0+b1+b2))); ee = 0.0; vv = 0.0; if ( rh > 0.0 ) { double ro13 = cbrt(rh); double rs = c1 / ro13; double ex=0.0,vx=0.0,ec=0.0,vc=0.0; // Next line : exchange part in Hartree units vx = c4 / rs; ex = 0.75 * vx; // Next lines : Ceperley & Alder correlation (Zunger & Perdew) if ( rs < 1.0 ) { double logrs = log(rs); ec = A * logrs + B + C * rs * logrs + D * rs; vc = A * logrs + ( B - A / 3.0 ) + (2.0/3.0) * C * rs * logrs + ( ( 2.0 * D - C ) / 3.0 ) * rs; } else { double sqrtrs = sqrt(rs); double den = 1.0 + b1 * sqrtrs + b2 * rs; ec = G / den; vc = ec * ( 1.0 + (7.0/6.0) * b1 * sqrtrs + (4.0/3.0) * b2 * rs ) / den; } ee = ex + ec; vv = vx + vc; } }