//////////////////////////////////////////////////////////////////////////////// // // 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 . // //////////////////////////////////////////////////////////////////////////////// // // B3LYPFunctional.C // //////////////////////////////////////////////////////////////////////////////// #include #include #include "B3LYPFunctional.h" #include "BLYPFunctional.h" #include "VWNFunctional.h" using namespace std; //////////////////////////////////////////////////////////////////////////////// B3LYPFunctional::B3LYPFunctional(const vector > &rhoe) { _nspin = rhoe.size(); if ( _nspin > 1 ) assert(rhoe[0].size() == rhoe[1].size()); _np = rhoe[0].size(); if ( _nspin == 1 ) { _exc.resize(_np); _vxc1.resize(_np); _vxc2.resize(_np); _grad_rho[0].resize(_np); _grad_rho[1].resize(_np); _grad_rho[2].resize(_np); rho = &rhoe[0][0]; grad_rho[0] = &_grad_rho[0][0]; grad_rho[1] = &_grad_rho[1][0]; grad_rho[2] = &_grad_rho[2][0]; exc = &_exc[0]; vxc1 = &_vxc1[0]; vxc2 = &_vxc2[0]; } else { _exc_up.resize(_np); _exc_dn.resize(_np); _vxc1_up.resize(_np); _vxc1_dn.resize(_np); _vxc2_upup.resize(_np); _vxc2_updn.resize(_np); _vxc2_dnup.resize(_np); _vxc2_dndn.resize(_np); _grad_rho_up[0].resize(_np); _grad_rho_up[1].resize(_np); _grad_rho_up[2].resize(_np); _grad_rho_dn[0].resize(_np); _grad_rho_dn[1].resize(_np); _grad_rho_dn[2].resize(_np); rho_up = &rhoe[0][0]; rho_dn = &rhoe[1][0]; grad_rho_up[0] = &_grad_rho_up[0][0]; grad_rho_up[1] = &_grad_rho_up[1][0]; grad_rho_up[2] = &_grad_rho_up[2][0]; grad_rho_dn[0] = &_grad_rho_dn[0][0]; grad_rho_dn[1] = &_grad_rho_dn[1][0]; grad_rho_dn[2] = &_grad_rho_dn[2][0]; exc_up = &_exc_up[0]; exc_dn = &_exc_dn[0]; vxc1_up = &_vxc1_up[0]; vxc1_dn = &_vxc1_dn[0]; vxc2_upup = &_vxc2_upup[0]; vxc2_updn = &_vxc2_updn[0]; vxc2_dnup = &_vxc2_dnup[0]; vxc2_dndn = &_vxc2_dndn[0]; } } //////////////////////////////////////////////////////////////////////////////// void B3LYPFunctional::setxc(void) { if ( _np == 0 ) return; if ( _nspin == 1 ) { assert( rho != 0 ); assert( grad_rho[0] != 0 && grad_rho[1] != 0 && grad_rho[2] != 0 ); assert( exc != 0 ); assert( vxc1 != 0 ); assert( vxc2 != 0 ); for ( int i = 0; i < _np; i++ ) { double grad = sqrt(grad_rho[0][i]*grad_rho[0][i] + grad_rho[1][i]*grad_rho[1][i] + grad_rho[2][i]*grad_rho[2][i] ); excb3lyp(rho[i],grad,&exc[i],&vxc1[i],&vxc2[i]); } } else { assert( rho_up != 0 ); assert( rho_dn != 0 ); assert( grad_rho_up[0] != 0 && grad_rho_up[1] != 0 && grad_rho_up[2] != 0 ); assert( grad_rho_dn[0] != 0 && grad_rho_dn[1] != 0 && grad_rho_dn[2] != 0 ); assert( exc_up != 0 ); assert( exc_dn != 0 ); assert( vxc1_up != 0 ); assert( vxc1_dn != 0 ); assert( vxc2_upup != 0 ); assert( vxc2_updn != 0 ); assert( vxc2_dnup != 0 ); assert( vxc2_dndn != 0 ); for ( int i = 0; i < _np; i++ ) { double grx_up = grad_rho_up[0][i]; double gry_up = grad_rho_up[1][i]; double grz_up = grad_rho_up[2][i]; double grx_dn = grad_rho_dn[0][i]; double gry_dn = grad_rho_dn[1][i]; double grz_dn = grad_rho_dn[2][i]; double grad_up2 = grx_up*grx_up + gry_up*gry_up + grz_up*grz_up; double grad_dn2 = grx_dn*grx_dn + gry_dn*gry_dn + grz_dn*grz_dn; double grad_up_grad_dn = grx_up*grx_dn + gry_up*gry_dn + grz_up*grz_dn; excb3lyp_sp(rho_up[i],rho_dn[i],grad_up2,grad_dn2,grad_up_grad_dn, &exc_up[i],&exc_dn[i],&vxc1_up[i],&vxc1_dn[i], &vxc2_upup[i],&vxc2_dndn[i], &vxc2_updn[i],&vxc2_dnup[i]); } } } //////////////////////////////////////////////////////////////////////////////// void B3LYPFunctional::excb3lyp(double rho, double grad, double *exc, double *vxc1, double *vxc2) { // B3LYP unpolarized // Coefficients of the B3LYP functional // A. Becke, JCP 98, 5648 (1993) // See also X.Xu and W. Goddard, J.Phys.Chem. A108, 2305 (2004) // EcLSDA is the Vosko-Wilk-Nusair correlation energy // dExBecke88 is the difference ExB88 - ExLDA // 0.2 ExHF + 0.80 ExSlater + 0.19 EcLSDA + 0.81 EcLYP + 0.72 dExBecke88 const double xlda_coeff = 0.80; // Slater exchange const double clda_coeff = 0.19; // LSDA correlation const double xb88_coeff = 0.72; // Becke88 exchange gradient correction const double clyp_coeff = 1.0 - clda_coeff; double ex_lda,vx_lda,ec_lda,vc_lda; double ex_b88,vx1_b88,vx2_b88; double ec_lyp,vc1_lyp,vc2_lyp; VWNFunctional::exvwn(rho,ex_lda,vx_lda); VWNFunctional::ecvwn(rho,ec_lda,vc_lda); BLYPFunctional::exb88(rho,grad,&ex_b88,&vx1_b88,&vx2_b88); BLYPFunctional::eclyp(rho,grad,&ec_lyp,&vc1_lyp,&vc2_lyp); const double dex_b88 = ex_b88 - ex_lda; const double dvx1_b88 = vx1_b88 - vx_lda; const double dvx2_b88 = vx2_b88; *exc = xlda_coeff * ex_lda + clda_coeff * ec_lda + xb88_coeff * dex_b88 + clyp_coeff * ec_lyp; *vxc1 = xlda_coeff * vx_lda + clda_coeff * vc_lda + xb88_coeff * dvx1_b88 + clyp_coeff * vc1_lyp; *vxc2 = xb88_coeff * dvx2_b88 + clyp_coeff * vc2_lyp; } //////////////////////////////////////////////////////////////////////////////// void B3LYPFunctional::excb3lyp_sp(double rho_up, double rho_dn, double grad_up2, double grad_dn2, double grad_up_grad_dn, double *exc_up, double *exc_dn, double *vxc1_up, double *vxc1_dn, double *vxc2_upup, double *vxc2_dndn, double *vxc2_updn, double *vxc2_dnup) { // B3LYP spin-polarized // Coefficients of the B3LYP functional // A. Becke, JCP 98, 5648 (1993) // See also X.Xu and W. Goddard, J.Phys.Chem. A108, 2305 (2004) // EcLSDA is the Vosko-Wilk-Nusair correlation energy // dExBecke88 is the difference ExB88 - ExLDA // 0.2 ExHF + 0.80 ExSlater + 0.19 EcLSDA + 0.81 EcLYP + 0.72 dExBecke88 const double xlda_coeff = 0.80; // Slater exchange const double clda_coeff = 0.19; // LSDA correlation const double xb88_coeff = 0.72; // Becke88 exchange gradient correction const double clyp_coeff = 1.0 - clda_coeff; double ex_lda,vx_lda_up,vx_lda_dn; double ec_lda,vc_lda_up,vc_lda_dn; double ex_b88_up,ex_b88_dn,vx1_b88_up,vx1_b88_dn, vx2_b88_upup,vx2_b88_dndn,vx2_b88_updn,vx2_b88_dnup; double ec_lyp_up,ec_lyp_dn,vc1_lyp_up,vc1_lyp_dn, vc2_lyp_upup,vc2_lyp_dndn,vc2_lyp_updn,vc2_lyp_dnup; VWNFunctional::exvwn_sp(rho_up,rho_dn,ex_lda,vx_lda_up,vx_lda_dn); VWNFunctional::ecvwn_sp(rho_up,rho_dn,ec_lda,vc_lda_up,vc_lda_dn); BLYPFunctional::exb88_sp(rho_up,rho_dn,grad_up2,grad_dn2,grad_up_grad_dn, &ex_b88_up,&ex_b88_dn,&vx1_b88_up,&vx1_b88_dn, &vx2_b88_upup,&vx2_b88_dndn,&vx2_b88_updn,&vx2_b88_dnup); BLYPFunctional::eclyp_sp(rho_up,rho_dn,grad_up2,grad_dn2,grad_up_grad_dn, &ec_lyp_up,&ec_lyp_dn,&vc1_lyp_up,&vc1_lyp_dn, &vc2_lyp_upup,&vc2_lyp_dndn,&vc2_lyp_updn,&vc2_lyp_dnup); const double dex_b88_up = ex_b88_up - ex_lda; const double dex_b88_dn = ex_b88_dn - ex_lda; const double dvx1_b88_up = vx1_b88_up - vx_lda_up; const double dvx1_b88_dn = vx1_b88_dn - vx_lda_dn; const double dvx2_b88_upup = vx2_b88_upup; const double dvx2_b88_dndn = vx2_b88_dndn; const double dvx2_b88_updn = vx2_b88_updn; const double dvx2_b88_dnup = vx2_b88_dnup; *exc_up = xlda_coeff * ex_lda + clda_coeff * ec_lda + xb88_coeff * dex_b88_up + clyp_coeff * ec_lyp_up; *exc_dn = xlda_coeff * ex_lda + clda_coeff * ec_lda + xb88_coeff * dex_b88_dn + clyp_coeff * ec_lyp_dn; *vxc1_up = xlda_coeff * vx_lda_up + clda_coeff * vc_lda_up + xb88_coeff * dvx1_b88_up + clyp_coeff * vc1_lyp_up; *vxc1_dn = xlda_coeff * vx_lda_dn + clda_coeff * vc_lda_dn + xb88_coeff * dvx1_b88_dn + clyp_coeff * vc1_lyp_dn; *vxc2_upup = xb88_coeff * dvx2_b88_upup + clyp_coeff * vc2_lyp_upup; *vxc2_dndn = xb88_coeff * dvx2_b88_dndn + clyp_coeff * vc2_lyp_dndn; *vxc2_updn = xb88_coeff * dvx2_b88_updn + clyp_coeff * vc2_lyp_updn; *vxc2_dnup = xb88_coeff * dvx2_b88_dnup + clyp_coeff * vc2_lyp_dnup; }