// // functional.cc // // Copyright (C) 1997 Limit Point Systems, Inc. // // Author: Curtis Janssen // Maintainer: LPS // // This file is part of the SC Toolkit. // // The SC Toolkit is free software; you can redistribute it and/or modify // it under the terms of the GNU Library General Public License as published by // the Free Software Foundation; either version 2, or (at your option) // any later version. // // The SC Toolkit is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Library General Public License for more details. // // You should have received a copy of the GNU Library General Public License // along with the SC Toolkit; see the file COPYING.LIB. If not, write to // the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. // // The U.S. Government is granted a limited license as per AL 91-7. // #ifdef __GNUC__ #pragma implementation #endif #include #include #include #include using namespace std; using namespace sc; #ifndef HAVE_ISNAN #define isnan(x) ((x)!=(x)) #endif #define MIN_DENSITY 1.e-14 #define MIN_GAMMA 1.e-24 #define MIN_SQRTGAMMA 1.e-12 #define MAX_ZETA 1.-1.e-12 #define MIN_ZETA -(1.-1.e-12) /////////////////////////////////////////////////////////////////////////// // utility functions inline static double norm(double v[3]) { double x,y,z; return sqrt((x=v[0])*x + (y=v[1])*y + (z=v[2])*z); } inline static double dot(double v[3], double w[3]) { return v[0]*w[0] + v[1]*w[1] + v[2]*w[2]; } /////////////////////////////////////////////////////////////////////////// // PointInputData void PointInputData::compute_derived(int spin_polarized, int need_gradient, int need_hessian) { a.rho_13 = pow(a.rho, 1.0/3.0); if (need_gradient) { a.gamma = dot(a.del_rho,a.del_rho); } if (need_hessian) { a.lap_rho = a.hes_rho[XX] + a.hes_rho[YY] + a.hes_rho[ZZ]; } if (spin_polarized) { b.rho_13 = pow(b.rho, 1.0/3.0); if (need_gradient) { b.gamma = dot(b.del_rho,b.del_rho); } if (need_hessian) { b.lap_rho = b.hes_rho[XX] + b.hes_rho[YY] + b.hes_rho[ZZ]; } } else { b = a; if (need_gradient) gamma_ab = a.gamma; } if (spin_polarized && need_gradient) { gamma_ab = a.del_rho[0]*b.del_rho[0] + a.del_rho[1]*b.del_rho[1] + a.del_rho[2]*b.del_rho[2]; } } /////////////////////////////////////////////////////////////////////////// // DenFunctional static ClassDesc DenFunctional_cd( typeid(DenFunctional),"DenFunctional",1,"public SavableState", 0, 0, 0); DenFunctional::DenFunctional(StateIn& s): SavableState(s) { s.get(a0_); s.get(spin_polarized_); s.get(compute_potential_); } DenFunctional::DenFunctional() { a0_ = 0; spin_polarized_ = 0; compute_potential_ = 0; } DenFunctional::DenFunctional(const Ref& keyval) { // a0 is usually zero, except for ACM functionals. a0_ = keyval->doublevalue("a0"); spin_polarized_ = 0; compute_potential_ = 0; } DenFunctional::~DenFunctional() { } void DenFunctional::save_data_state(StateOut& s) { s.put(a0_); s.put(spin_polarized_); s.put(compute_potential_); } double DenFunctional::a0() const { return a0_; } int DenFunctional::need_density_gradient() { return 0; } int DenFunctional::need_density_hessian() { return 0; } void DenFunctional::set_spin_polarized(int i) { spin_polarized_ = i; } void DenFunctional::set_compute_potential(int i) { compute_potential_ = i; } void DenFunctional::gradient(const PointInputData& id, PointOutputData& od, double *grad_f, int acenter, GaussianBasisSet *basis, const double *dmat_a, const double *dmat_b, int ncontrib, const int *contrib, int ncontrib_bf, const int *contrib_bf, const double *bs, const double *bsg, const double *bsh) { int need_gamma_terms = need_density_gradient(); point(id, od); memset(grad_f, 0, sizeof(double)*basis->ncenter()*3); #if 0 ExEnv::outn() << scprintf("gradient: rho_a= %12.8f rho_b= %12.8f need_gamma = %d", id.a.rho, id.b.rho, need_gamma_terms) << endl; ExEnv::outn() << scprintf(" gamma_aa= %12.8f gamma_bb= %12.8f gamma_ab= % 12.8f", id.a.gamma, id.b.gamma, id.gamma_ab) << endl; ExEnv::outn() << scprintf(" df_drho_a= % 12.8f df_drho_b= % 12.8f", od.df_drho_a, od.df_drho_b) << endl; ExEnv::outn() << scprintf(" df_dg_aa= % 12.8f df_dg_bb= % 12.8f df_dg_ab= % 12.8f", od.df_dgamma_aa,od.df_dgamma_bb,od.df_dgamma_ab) << endl; #endif if (need_gamma_terms) { double drhoa = od.df_drho_a; double drhob = od.df_drho_b; for (int nu=0; nushell_to_center(basis->function_to_shell(nut)); double dfa_phi_nu = drhoa * bs[nu]; double dfb_phi_nu = drhob * bs[nu]; for (int mu=0; mushell_to_center(basis->function_to_shell(mut)); if (muatom!=acenter) { int nutmut = (nut>mut?((nut*(nut+1))/2+mut):((mut*(mut+1))/2+nut)); double rho_a = dmat_a[nutmut]; double rho_b = dmat_b[nutmut]; int ixyz; for (ixyz=0; ixyz<3; ixyz++) { double contrib = -2.0*bsg[mu*3+ixyz] * (rho_a*dfa_phi_nu + rho_b*dfb_phi_nu); #define hoff(i,j) ((j)<(i)?((i)*((i)+1))/2+(j):((j)*((j)+1))/2+(i)) // gamma_aa contrib if (need_gamma_terms) { contrib += 4.0 * od.df_dgamma_aa * rho_a * ( - bsg[mu*3+ixyz] * ( id.a.del_rho[0]*bsg[nu*3+0] +id.a.del_rho[1]*bsg[nu*3+1] +id.a.del_rho[2]*bsg[nu*3+2]) - bs[nu] * ( id.a.del_rho[0]*bsh[mu*6+hoff(0,ixyz)] +id.a.del_rho[1]*bsh[mu*6+hoff(1,ixyz)] +id.a.del_rho[2]*bsh[mu*6+hoff(2,ixyz)] ) ); } // gamma_ab contrib if (need_gamma_terms) { contrib += 2.0 * od.df_dgamma_ab * rho_a * ( - bsg[mu*3+ixyz] * ( id.b.del_rho[0]*bsg[nu*3+0] +id.b.del_rho[1]*bsg[nu*3+1] +id.b.del_rho[2]*bsg[nu*3+2]) - bs[nu] * ( id.b.del_rho[0]*bsh[mu*6+hoff(0,ixyz)] +id.b.del_rho[1]*bsh[mu*6+hoff(1,ixyz)] +id.b.del_rho[2]*bsh[mu*6+hoff(2,ixyz)] ) ); contrib += 2.0 * od.df_dgamma_ab * rho_b * ( - bsg[mu*3+ixyz] * ( id.a.del_rho[0]*bsg[nu*3+0] +id.a.del_rho[1]*bsg[nu*3+1] +id.a.del_rho[2]*bsg[nu*3+2]) - bs[nu] * ( id.a.del_rho[0]*bsh[mu*6+hoff(0,ixyz)] +id.a.del_rho[1]*bsh[mu*6+hoff(1,ixyz)] +id.a.del_rho[2]*bsh[mu*6+hoff(2,ixyz)] ) ); } // gamma_bb contrib if (need_gamma_terms) { contrib += 4.0 * od.df_dgamma_bb * rho_b * ( - bsg[mu*3+ixyz] * ( id.b.del_rho[0]*bsg[nu*3+0] +id.b.del_rho[1]*bsg[nu*3+1] +id.b.del_rho[2]*bsg[nu*3+2]) - bs[nu] * ( id.b.del_rho[0]*bsh[mu*6+hoff(0,ixyz)] +id.b.del_rho[1]*bsh[mu*6+hoff(1,ixyz)] +id.b.del_rho[2]*bsh[mu*6+hoff(2,ixyz)] ) ); } grad_f[3*muatom+ixyz] += contrib; grad_f[3*acenter+ixyz] -= contrib; } } } } } else { double drhoa = od.df_drho_a; double drhob = od.df_drho_b; for (int nu=0; nushell_to_center(basis->function_to_shell(nut)); double dfa_phi_nu = drhoa * bs[nu]; double dfb_phi_nu = drhob * bs[nu]; for (int mu=0; mushell_to_center(basis->function_to_shell(mut)); if (muatom!=acenter) { int nutmut = (nut>mut?((nut*(nut+1))/2+mut):((mut*(mut+1))/2+nut)); double rho_a = dmat_a[nutmut]; double rho_b = dmat_b[nutmut]; int ixyz; for (ixyz=0; ixyz<3; ixyz++) { // std::cout << "bsg[mu*3+ixyz] = " << bsg[mu*3+ixyz] // << std::endl; // std::cout << "rho_a = " << rho_a // << std::endl; // std::cout << "rho_b = " << rho_b // << std::endl; // std::cout << "dfa_phi_nu = " << dfa_phi_nu // << std::endl; // std::cout << "dfb_phi_nu = " << dfb_phi_nu // << std::endl; double contrib = -2.0*bsg[mu*3+ixyz] * (rho_a*dfa_phi_nu + rho_b*dfb_phi_nu); grad_f[3*muatom+ixyz] += contrib; grad_f[3*acenter+ixyz] -= contrib; } } } } } } void DenFunctional::do_fd_point(PointInputData&id, double&in,double&out, double lower_bound, double upper_bound) { double delta = 0.0000000001; PointOutputData tod; double insave = in; point(id,tod); double outsave = tod.energy; int spin_polarized_save = spin_polarized_; set_spin_polarized(1); if (insave-delta>=lower_bound && insave+delta<=upper_bound) { in = insave+delta; id.compute_derived(1, need_density_gradient(), false); point(id,tod); double plus = tod.energy; in = insave-delta; id.compute_derived(1, need_density_gradient(), false); point(id,tod); double minu = tod.energy; out = 0.5*(plus-minu)/delta; } else if (insave+2*delta<=upper_bound) { in = insave+delta; id.compute_derived(1, need_density_gradient(), false); point(id,tod); double plus = tod.energy; in = insave+2*delta; id.compute_derived(1, need_density_gradient(), false); point(id,tod); double plus2 = tod.energy; out = 0.5*(4.0*plus-plus2-3.0*outsave)/delta; } else if (insave-2*delta>=lower_bound) { in = insave-delta; id.compute_derived(1, need_density_gradient(), false); point(id,tod); double minu = tod.energy; in = insave-2*delta; id.compute_derived(1, need_density_gradient(), false); point(id,tod); double minu2 = tod.energy; out = -0.5*(4.0*minu-minu2-3.0*outsave)/delta; } else { // the derivative is not well defined for this case out = -135711.; } in = insave; id.compute_derived(1, need_density_gradient(), false); set_spin_polarized(spin_polarized_save); } void DenFunctional::fd_point(const PointInputData&id, PointOutputData&od) { PointInputData tid(id); // fill in the energy at the initial density values point(id,od); ExEnv::out0() << scprintf("ra=%7.5f rb=%7.5f gaa=%7.5f gbb=%7.5f gab= % 9.7f", id.a.rho, id.b.rho, id.a.gamma, id.b.gamma, id.gamma_ab) << endl; double ga = tid.a.gamma; double gb = tid.b.gamma; double gab = tid.gamma_ab; double sga = sqrt(ga); double sgb = sqrt(gb); double g_a_lbound = -2*gab - gb; if (gb > 0 && gab*gab/gb > g_a_lbound) g_a_lbound = gab*gab/gb; if (g_a_lbound < 0) g_a_lbound = 0.0; double g_b_lbound = -2*gab - ga; if (ga > 0 && gab*gab/ga > g_b_lbound) g_b_lbound = gab*gab/ga; if (g_b_lbound < 0) g_b_lbound = 0.0; double g_ab_lbound = -0.5*(ga+gb); if (-sga*sgb > g_ab_lbound) g_ab_lbound = -sga*sgb; // if (-sga*sgb < g_ab_lbound) g_ab_lbound = -sga*sgb; double g_ab_ubound = sga*sgb; do_fd_point(tid, tid.a.rho, od.df_drho_a, 0.0, 10.0); do_fd_point(tid, tid.b.rho, od.df_drho_b, 0.0, 10.0); do_fd_point(tid, tid.a.gamma, od.df_dgamma_aa, g_a_lbound, 10.0); do_fd_point(tid, tid.b.gamma, od.df_dgamma_bb, g_b_lbound, 10.0); do_fd_point(tid, tid.gamma_ab, od.df_dgamma_ab, g_ab_lbound, g_ab_ubound); } static int check(const char *name, double fd, double an, const char *class_name) { // -135711. flags an undefined FD if (fd == -135711.) return 0; double err = fabs(fd - an); ExEnv::out0() << scprintf("%20s: fd = % 12.8f an = % 12.8f", name, fd, an) << endl; if ((fabs(an) > 0.03 && err/fabs(an) > 0.03) || ((fabs(an) <= 0.03) && err > 0.03) #ifdef HAVE_ISNAN || isnan(an) #endif ) { ExEnv::out0() << scprintf("Error: %12s: fd = % 12.8f an = % 12.8f (%s)", name, fd, an, class_name) << endl; return 1; } return 0; } int DenFunctional::test(const PointInputData &id) { PointOutputData fd_od; fd_point(id,fd_od); PointOutputData an_od; point(id,an_od); int r = 0; r+=check("df_drho_a", fd_od.df_drho_a, an_od.df_drho_a, class_name()); r+=check("df_drho_b", fd_od.df_drho_b, an_od.df_drho_b, class_name()); r+=check("df_dgamma_aa",fd_od.df_dgamma_aa,an_od.df_dgamma_aa,class_name()); r+=check("df_dgamma_ab",fd_od.df_dgamma_ab,an_od.df_dgamma_ab,class_name()); r+=check("df_dgamma_bb",fd_od.df_dgamma_bb,an_od.df_dgamma_bb,class_name()); return r; } int DenFunctional::test() { int i, j, k, l, m; set_compute_potential(1); set_spin_polarized(0); SCVector3 r = 0.0; PointInputData id(r); for (i=0; i<6; i++) id.a.hes_rho[i] = 0.0; id.a.lap_rho = 0.0; // del rho should not be used by any of the functionals for (i=0; i<3; i++) id.a.del_rho[i] = id.b.del_rho[i] = 0.0; double testrho[] = { 0.0, 0.001, 0.5, -1 }; double testgamma[] = { 0.0, 0.001, 0.5, -1 }; double testgammaab[] = { -0.5, 0.0, 0.5, -1 }; int ret = 0; ExEnv::out0() << "Testing with rho_a == rho_b" << endl; for (i=0; testrho[i] != -1.0; i++) { if (testrho[i] == 0.0) continue; id.a.rho=testrho[i]; for (j=0; testgamma[j] != -1.0; j++) { if (testgamma[j] > testrho[i]) continue; id.a.gamma = testgamma[j]; id.compute_derived(0, need_density_gradient(), false); ret += test(id); } } set_spin_polarized(1); ExEnv::out0() << "Testing with rho_a != rho_b" << endl; for (i=0; testrho[i] != -1.0; i++) { id.a.rho=testrho[i]; for (j=0; testrho[j] != -1.0; j++) { id.b.rho=testrho[j]; if (testrho[i]+testrho[j] == 0.0) continue; for (k=0; testgamma[k] != -1.0; k++) { if (testgamma[k] > testrho[i]) continue; id.a.gamma = testgamma[k]; double sqrt_gamma_a = sqrt(id.a.gamma); for (l=0; testgamma[l] != -1.0; l++) { if (testgamma[l] > testrho[j]) continue; id.b.gamma = testgamma[l]; double sqrt_gamma_b = sqrt(id.b.gamma); for (m=0; testgammaab[m] != -1.0; m++) { // constrain gamma_ab to values allowed by the // current gamma_a and gamma_b id.gamma_ab = testgammaab[m]; if (id.gamma_ab > sqrt_gamma_a*sqrt_gamma_b) { id.gamma_ab = sqrt_gamma_a*sqrt_gamma_b; } if (id.gamma_ab < -0.5*(id.a.gamma+id.b.gamma)) { id.gamma_ab = -0.5*(id.a.gamma+id.b.gamma); } if (id.gamma_ab < -sqrt_gamma_a*sqrt_gamma_b) { id.gamma_ab = -sqrt_gamma_a*sqrt_gamma_b; } id.compute_derived(1, need_density_gradient(), false); ret += test(id); } } } } } return ret; } ///////////////////////////////////////////////////////////////////////////// // NElFunctional static ClassDesc NElFunctional_cd( typeid(NElFunctional),"NElFunctional",1,"public DenFunctional", 0, create, create); NElFunctional::NElFunctional(StateIn& s): SavableState(s), DenFunctional(s) { } NElFunctional::NElFunctional(const Ref& keyval): DenFunctional(keyval) { } NElFunctional::~NElFunctional() { } void NElFunctional::save_data_state(StateOut& s) { DenFunctional::save_data_state(s); } void NElFunctional::point(const PointInputData &id, PointOutputData &od) { od.zero(); od.energy = id.a.rho + id.b.rho; } ///////////////////////////////////////////////////////////////////////////// // SumDenFunctional static ClassDesc SumDenFunctional_cd( typeid(SumDenFunctional),"SumDenFunctional",1,"public DenFunctional", 0, create, create); SumDenFunctional::SumDenFunctional(StateIn& s): SavableState(s), DenFunctional(s), n_(0), funcs_(0), coefs_(0) { s.get(n_); if (n_) { s.get(coefs_); funcs_ = new Ref[n_]; for (int i=0; i < n_; i++) funcs_[i] << SavableState::restore_state(s); } } SumDenFunctional::SumDenFunctional() : n_(0), funcs_(0), coefs_(0) { } SumDenFunctional::SumDenFunctional(const Ref& keyval): DenFunctional(keyval), n_(0), funcs_(0), coefs_(0) { int ncoef = keyval->count("coefs"); int nfunc = keyval->count("funcs"); if (ncoef != nfunc && ncoef != 0) { ExEnv::out0() << "SumDenFunctional: number of coefs and funcs differ" << endl; abort(); } n_ = nfunc; coefs_ = new double[n_]; funcs_ = new Ref[n_]; for (int i=0; i < n_; i++) { if (ncoef) coefs_[i] = keyval->doublevalue("coefs", i); else coefs_[i] = 1.0; funcs_[i] << keyval->describedclassvalue("funcs", i); } } SumDenFunctional::~SumDenFunctional() { if (n_) { for (int i=0; i < n_; i++) funcs_[i] = 0; // just in case delete[] funcs_; delete[] coefs_; } n_=0; funcs_=0; coefs_=0; } void SumDenFunctional::save_data_state(StateOut& s) { DenFunctional::save_data_state(s); s.put(n_); if (n_) { s.put(coefs_, n_); for (int i=0; i < n_; i++) SavableState::save_state(funcs_[i].pointer(),s); } } double SumDenFunctional::a0() const { double eff_a0 = a0_; for (int i=0; i < n_; i++) { eff_a0 += coefs_[i] * funcs_[i]->a0(); } return eff_a0; } int SumDenFunctional::need_density_gradient() { for (int i=0; i < n_; i++) if (funcs_[i]->need_density_gradient()) return 1; return 0; } void SumDenFunctional::set_spin_polarized(int p) { spin_polarized_ = p; for (int i=0; i < n_; i++) funcs_[i]->set_spin_polarized(p); } void SumDenFunctional::set_compute_potential(int val) { compute_potential_ = val; for (int i=0; i < n_; i++) funcs_[i]->set_compute_potential(val); } void SumDenFunctional::point(const PointInputData &id, PointOutputData &od) { od.zero(); PointOutputData tmpod; for (int i=0; i < n_; i++) { funcs_[i]->point(id, tmpod); od.energy += coefs_[i] * tmpod.energy; if (compute_potential_) { od.df_drho_a += coefs_[i] * tmpod.df_drho_a; od.df_drho_b += coefs_[i] * tmpod.df_drho_b; od.df_dgamma_aa += coefs_[i] * tmpod.df_dgamma_aa; od.df_dgamma_ab += coefs_[i] * tmpod.df_dgamma_ab; od.df_dgamma_bb += coefs_[i] * tmpod.df_dgamma_bb; } } } void SumDenFunctional::print(ostream& o) const { o << indent << "Sum of Functionals:" << endl; o << incindent; o << indent << scprintf("%+18.16f Hartree-Fock Exchange",a0_) << endl; for (int i=0; iprint(o); o << decindent; } o << decindent; } ///////////////////////////////////////////////////////////////////////////// // StdDenFunctional static ClassDesc StdDenFunctional_cd( typeid(StdDenFunctional),"StdDenFunctional",1,"public SumDenFunctional", 0, create, create); StdDenFunctional::StdDenFunctional(StateIn& s): SavableState(s), SumDenFunctional(s), name_(0) { s.getstring(name_); } StdDenFunctional::StdDenFunctional(): name_(0) { } void StdDenFunctional::init_arrays(int n) { n_ = n; funcs_ = new Ref[n_]; coefs_ = new double[n_]; for (int i=0; i& keyval) { name_ = keyval->pcharvalue("name"); if (name_) { if (!strcmp(name_,"HFK")) { n_ = 0; a0_ = 1.0; } else if (!strcmp(name_,"XALPHA")) { init_arrays(1); funcs_[0] = new XalphaFunctional; } else if (!strcmp(name_,"HFS")) { init_arrays(1); funcs_[0] = new SlaterXFunctional; } else if (!strcmp(name_,"HFB")) { init_arrays(2); funcs_[0] = new SlaterXFunctional; funcs_[1] = new Becke88XFunctional; } else if (!strcmp(name_,"HFG96")) { init_arrays(1); funcs_[0] = new G96XFunctional; } else if (!strcmp(name_,"G96LYP")) { init_arrays(2); funcs_[0] = new G96XFunctional; funcs_[1] = new LYPCFunctional; } else if (!strcmp(name_,"BLYP")) { init_arrays(3); funcs_[0] = new SlaterXFunctional; funcs_[1] = new Becke88XFunctional; funcs_[2] = new LYPCFunctional; } else if (!strcmp(name_,"SVWN1")) { init_arrays(2); funcs_[0] = new SlaterXFunctional; funcs_[1] = new VWN1LCFunctional; } else if (!strcmp(name_,"SVWN1RPA")) { init_arrays(2); funcs_[0] = new SlaterXFunctional; funcs_[1] = new VWN1LCFunctional(1); } else if (!strcmp(name_,"SVWN2")) { init_arrays(2); funcs_[0] = new SlaterXFunctional; funcs_[1] = new VWN2LCFunctional; } else if (!strcmp(name_,"SVWN3")) { init_arrays(2); funcs_[0] = new SlaterXFunctional; funcs_[1] = new VWN3LCFunctional; } else if (!strcmp(name_,"SVWN4")) { init_arrays(2); funcs_[0] = new SlaterXFunctional; funcs_[1] = new VWN4LCFunctional; } else if (!strcmp(name_,"SVWN5")) { init_arrays(2); funcs_[0] = new SlaterXFunctional; funcs_[1] = new VWN5LCFunctional; } else if (!strcmp(name_,"SPZ81")) { init_arrays(2); funcs_[0] = new SlaterXFunctional; funcs_[1] = new PZ81LCFunctional; } else if (!strcmp(name_,"SPW92")) { init_arrays(2); funcs_[0] = new SlaterXFunctional; funcs_[1] = new PW92LCFunctional; } else if (!strcmp(name_,"BPW91")) { init_arrays(3); funcs_[0] = new SlaterXFunctional; funcs_[1] = new Becke88XFunctional; funcs_[2] = new PW91CFunctional; } else if (!strcmp(name_,"BP86")) { init_arrays(4); funcs_[0] = new SlaterXFunctional; funcs_[1] = new Becke88XFunctional; funcs_[2] = new P86CFunctional; funcs_[3] = new PZ81LCFunctional; } else if (!strcmp(name_,"B3LYP")) { init_arrays(4); a0_ = 0.2; coefs_[0] = 0.8; coefs_[1] = 0.72; coefs_[2] = 0.19; coefs_[3] = 0.81; funcs_[0] = new SlaterXFunctional; funcs_[1] = new Becke88XFunctional; funcs_[2] = new VWN1LCFunctional(1); funcs_[3] = new LYPCFunctional; } else if (!strcmp(name_,"KMLYP")) { init_arrays(3); a0_ = 0.557; coefs_[0] = 0.443; coefs_[1] = 0.552; coefs_[2] = 0.448; funcs_[0] = new SlaterXFunctional; funcs_[1] = new VWN1LCFunctional(1); funcs_[2] = new LYPCFunctional; } else if (!strcmp(name_,"B3PW91")) { init_arrays(4); a0_ = 0.2; coefs_[0] = 0.8; coefs_[1] = 0.72; coefs_[2] = 0.81; coefs_[3] = 0.19; funcs_[0] = new SlaterXFunctional; funcs_[1] = new Becke88XFunctional; funcs_[2] = new PW91CFunctional; funcs_[3] = new PW92LCFunctional; } else if (!strcmp(name_,"B3P86")) { init_arrays(4); a0_ = 0.2; coefs_[0] = 0.8; coefs_[1] = 0.72; coefs_[2] = 0.81; coefs_[3] = 1.0; funcs_[0] = new SlaterXFunctional; funcs_[1] = new Becke88XFunctional; funcs_[2] = new P86CFunctional; funcs_[3] = new VWN1LCFunctional(1); } else if (!strcmp(name_,"PBE")) { init_arrays(2); funcs_[0] = new PBEXFunctional; funcs_[1] = new PBECFunctional; } else if (!strcmp(name_,"PW91")) { init_arrays(2); funcs_[0] = new PW91XFunctional; funcs_[1] = new PW91CFunctional; } else if (!strcmp(name_,"mPW(PW91)PW91")) { init_arrays(2); funcs_[0] = new mPW91XFunctional(mPW91XFunctional::PW91); funcs_[1] = new PW91CFunctional; } else if (!strcmp(name_,"mPWPW91")) { init_arrays(2); funcs_[0] = new mPW91XFunctional(mPW91XFunctional::mPW91); funcs_[1] = new PW91CFunctional; } else if (!strcmp(name_,"mPW1PW91")) { init_arrays(2); a0_ = 0.16; coefs_[0] = 0.84; coefs_[1] = 1.0; funcs_[0] = new mPW91XFunctional(mPW91XFunctional::mPW91); funcs_[1] = new PW91CFunctional; } else { ExEnv::out0() << "StdDenFunctional: bad name: " << name_ << endl; abort(); } } } StdDenFunctional::~StdDenFunctional() { delete[] name_; } void StdDenFunctional::save_data_state(StateOut& s) { SumDenFunctional::save_data_state(s); s.putstring(name_); } void StdDenFunctional::print(ostream& o) const { const char *n = name_; if (!n) n = "Null"; o << indent << "Standard Density Functional: " << n << endl; SumDenFunctional::print(o); } ///////////////////////////////////////////////////////////////////////////// // LSDACFunctional: All local correlation functionals inherit from this class. // Coded by Matt Leininger static ClassDesc LSDACFunctional_cd( typeid(LSDACFunctional),"LSDACFunctional",1,"public DenFunctional", 0, 0, 0); LSDACFunctional::LSDACFunctional(StateIn& s): SavableState(s), DenFunctional(s) { } LSDACFunctional::LSDACFunctional() { } LSDACFunctional::LSDACFunctional(const Ref& keyval): DenFunctional(keyval) { } LSDACFunctional::~LSDACFunctional() { } void LSDACFunctional::save_data_state(StateOut& s) { DenFunctional::save_data_state(s); } void LSDACFunctional::point(const PointInputData &id, PointOutputData &od) { double junk_1, junk_2, junk_3; point_lc(id, od, junk_1, junk_2, junk_3); } ///////////////////////////////////////////////////////////////////////////// // SlaterXFunctional static ClassDesc SlaterXFunctional_cd( typeid(SlaterXFunctional),"SlaterXFunctional",1,"public DenFunctional", 0, create, create); SlaterXFunctional::SlaterXFunctional(StateIn& s): SavableState(s), DenFunctional(s) { } SlaterXFunctional::SlaterXFunctional() { } SlaterXFunctional::SlaterXFunctional(const Ref& keyval): DenFunctional(keyval) { } SlaterXFunctional::~SlaterXFunctional() { } void SlaterXFunctional::save_data_state(StateOut& s) { DenFunctional::save_data_state(s); } void SlaterXFunctional::point(const PointInputData &id, PointOutputData &od) { const double mcx2rthird = -0.9305257363491; // -1.5*(3/4pi)^1/3 const double dmcx2rthird = -1.2407009817988; // 2*(3/4pi)^1/3 od.zero(); if (!spin_polarized_) { od.energy = mcx2rthird * 2.0 * id.a.rho * id.a.rho_13; if (compute_potential_) { od.df_drho_a = dmcx2rthird * id.a.rho_13; od.df_drho_b = od.df_drho_a; } } else { od.energy = mcx2rthird * (id.a.rho * id.a.rho_13 + id.b.rho * id.b.rho_13); if (compute_potential_) { od.df_drho_a = dmcx2rthird * id.a.rho_13; od.df_drho_b = dmcx2rthird * id.b.rho_13; } } } ///////////////////////////////////////////////////////////////////////////// // PW92LCFunctional // Coded by Matt Leininger static ClassDesc PW92LCFunctional_cd( typeid(PW92LCFunctional),"PW92LCFunctional",1,"public LSDACFunctional", 0, create, create); PW92LCFunctional::PW92LCFunctional(StateIn& s): SavableState(s), LSDACFunctional(s) { } PW92LCFunctional::PW92LCFunctional() { } PW92LCFunctional::PW92LCFunctional(const Ref& keyval): LSDACFunctional(keyval) { } PW92LCFunctional::~PW92LCFunctional() { } void PW92LCFunctional::save_data_state(StateOut& s) { LSDACFunctional::save_data_state(s); } double PW92LCFunctional::F(double x, double A, double alpha_1, double beta_1, double beta_2, double beta_3, double beta_4, double p) { double x2 = x*x; // r_s double denom = 2.*A*( beta_1 * x + beta_2 * x2 + beta_3 * x2*x + beta_4 * pow(x2,p+1.)); double res = -2.*A*(1. + alpha_1*x2)*log(1.+ 1./denom); return res; } double PW92LCFunctional::dFdr_s(double x, double A, double alpha_1, double beta_1, double beta_2, double beta_3, double beta_4, double p) { double x2 = x*x; // r_s double Q_0 = -2.*A*(1. + alpha_1*x2); double Q_1 = 2.*A*(beta_1 * x + beta_2 * x2 + beta_3*x*x2 + beta_4 * pow(x2,p+1.)); double Q_1prime = A * ( beta_1 * 1./x + 2.*beta_2 + 3.*beta_3*x + 2.*(p+1.)*beta_4*pow(x2,p)); double res = -2.*A*alpha_1*log(1. + 1./Q_1) - Q_0*Q_1prime/(Q_1*Q_1 + Q_1); return res; } void PW92LCFunctional::point_lc(const PointInputData &id, PointOutputData &od, double &ec_local, double &decrs, double &deczeta) { od.zero(); const double fpp0 = 4./9. * 1./(pow(2., (1./3.)) - 1.); const double sixth = 1./6.; const double four_thirds = 4./3.; const double one_third = 1./3.; const double two_thirds = 2./3.; double rho = id.a.rho + id.b.rho; double zeta = (id.a.rho - id.b.rho)/rho; double x = pow(3./(4.*M_PI*rho), sixth); double rs = x*x; double epc = F(x, 0.0310907, 0.21370, 7.5957, 3.5876, 1.6382, 0.49294, 1.00); double efc = F(x, 0.01554535, 0.20548, 14.1189, 6.1977, 3.3662, 0.62517, 1.00); double alphac = F(x, 0.0168869, 0.11125, 10.357, 3.6231, 0.88026, 0.49671, 1.00); double f = 9./8.*fpp0*(pow(1.+zeta, four_thirds)+pow(1.-zeta, four_thirds)-2.); double zeta2 = zeta*zeta; double zeta4 = zeta2*zeta2; double delta_ec = -alphac * f / fpp0 * (1. - zeta4) + (efc - epc) * f * zeta4; double ec = epc + delta_ec; od.energy = ec * rho; ec_local = ec; if (compute_potential_) { if (!spin_polarized_) { double depc_dr_s0 = dFdr_s(x, 0.0310907, 0.21370, 7.5957, 3.5876, 1.6382, 0.49294, 1.00); double dec_dr_s = depc_dr_s0; od.df_drho_a = od.df_drho_b = ec - (rs/3.)*dec_dr_s; decrs = dec_dr_s; deczeta = 0.; } else { double zeta3 = zeta2*zeta; double depc_dr_s0 = dFdr_s(x, 0.0310907, 0.21370, 7.5957, 3.5876, 1.6382, 0.49294, 1.00); double defc_dr_s1 = dFdr_s(x, 0.01554535, 0.20548, 14.1189, 6.1977, 3.3662, 0.62517, 1.00); double dalphac_dr_s = dFdr_s(x, 0.0168869, 0.11125, 10.357, 3.6231, 0.88026, 0.49671, 1.00); double dec_dr_s = depc_dr_s0*(1 - f*zeta4) + defc_dr_s1 * f * zeta4 + -dalphac_dr_s * f / fpp0 * (1 - zeta4); double fp = two_thirds * (pow((1+zeta),one_third) - pow((1-zeta),one_third))/(pow(2.,one_third)-1); double dec_dzeta = 4.* zeta3 * f * (efc - epc - (-alphac/fpp0)) + fp * (zeta4 * (efc - epc) + (1-zeta4)*(-alphac/fpp0)); od.df_drho_a = ec - (rs/3.)*dec_dr_s - (zeta-1)*dec_dzeta; od.df_drho_b = ec - (rs/3.)*dec_dr_s - (zeta+1)*dec_dzeta; decrs = dec_dr_s; deczeta = dec_dzeta; } } } ///////////////////////////////////////////////////////////////////////////// // PZ81LCFunctional // Coded by Matt Leininger // Used in P86 correlation functional // J. P. Perdew and A. Zunger, Phys. Rev. B, 23, 5048, 1981. // C. W. Murray, N. C. Handy, G. J. Laming, Mol. Phys., 78, 997, 1993. // static ClassDesc PZ81LCFunctional_cd( typeid(PZ81LCFunctional),"PZ81LCFunctional",1,"public LSDACFunctional", 0, create, create); PZ81LCFunctional::PZ81LCFunctional(StateIn& s): SavableState(s), LSDACFunctional(s) { } PZ81LCFunctional::PZ81LCFunctional() { } PZ81LCFunctional::PZ81LCFunctional(const Ref& keyval): LSDACFunctional(keyval) { } PZ81LCFunctional::~PZ81LCFunctional() { } void PZ81LCFunctional::save_data_state(StateOut& s) { LSDACFunctional::save_data_state(s); } double PZ81LCFunctional::Fec_rsgt1(double rs, double beta1, double beta2, double gamma) { double sqrt_rs = sqrt(rs); double res = gamma / (1. + beta1*sqrt_rs + beta2*rs); return res; } double PZ81LCFunctional::dFec_rsgt1_drho(double rs, double beta1, double beta2, double gamma, double &dec_drs) { double ec = Fec_rsgt1(rs, beta1, beta2, gamma); double sqrt_rs = sqrt(rs); // double numer = 1.+ 7./6.*beta1*sqrt_rs + 4./3.*beta2*rs; double denom = 1. + beta1*sqrt_rs + beta2*rs; dec_drs = -ec/denom * (beta1/(2.*sqrt_rs) + beta2); // double res = ec * numer / denom; double res = (ec - rs/3.*dec_drs); return res; } double PZ81LCFunctional::Fec_rslt1(double rs, double A, double B, double C, double D) { double lnrs = log(rs); double res = A*lnrs + B + C*rs*lnrs + D*rs; return res; } double PZ81LCFunctional::dFec_rslt1_drho(double rs, double A, double B, double C, double D, double &dec_drs) { double lnrs = log(rs); double res = A*lnrs + B - A/3. + 2./3.*C*rs*lnrs + 1./3.*(2.*D - C)*rs; dec_drs = A/rs + C*lnrs + C + D; return res; } void PZ81LCFunctional::point_lc(const PointInputData &id, PointOutputData &od, double &ec_local, double &decrs, double &deczeta) { od.zero(); const double Au = 0.0311; const double Ap = 0.01555; const double Bu = -0.048; const double Bp = -0.0269; const double Cu = 0.0020; const double Cp = 0.0007; const double Du = -0.0116; const double Dp = -0.0048; const double beta1u = 1.0529; const double beta1p = 1.3981; const double beta2u = 0.3334; const double beta2p = 0.2611; const double gammau = -0.1423; const double gammap = -0.0843; double rho = id.a.rho + id.b.rho; double zeta = (id.a.rho - id.b.rho)/rho; double rs = pow(3./(4.*M_PI*rho), (1./3.) ); double fzeta = ( pow((1.+zeta), (4./3.)) + pow((1.-zeta), (4./3.)) - 2.) / ( pow(2., (4./3.)) - 2. ); double euc, epc; if (rs >= 1.) { // Ceperley U // euc = Fec_rsgt1(rs, 1.1581, 0.3446, -0.1471); // Ceperley P // epc = Fec_rsgt1(rs, 1.2520, 0.2567, -0.0790); // Ceperley-Adler U euc = Fec_rsgt1(rs, beta1u, beta2u, gammau); // Ceperley-Adler P epc = Fec_rsgt1(rs, beta1p, beta2p, gammap); } else { // rs < 1. // Ceperley U with A_u and B_u // euc = Fec_rslt1(rs, 0.0311, -0.048, 0.0014, -0.0108); // Ceperley P with A_p and B_p // epc = Fec_rslt1(rs, 0.01555, -0.0269, 0.0001, -0.0046); // Ceperley-Adler U with A_u and B_u euc = Fec_rslt1(rs, Au, Bu, Cu, Du); // Ceperley-Adler P with A_p and B_p epc = Fec_rslt1(rs, Ap, Bp, Cp, Dp); } double ec = euc + fzeta*(epc-euc); ec_local = ec; od.energy = ec * rho; if (compute_potential_) { double deuc_drs = 0.; double depc_drs = 0.; double deuc_drho, depc_drho; if (rs > 1.) { // Ceperley U // deuc_drho = dFec_rsgt1_drho(rs, 1.1581, 0.3446, -0.1471, deuc_drs); // Ceperley P // depc_drho = dFec_rsgt1_drho(rs, 1.2520, 0.2567, -0.0790, depc_drs); // Ceperley-Adler U deuc_drho = dFec_rsgt1_drho(rs, beta1u, beta2u, gammau, deuc_drs); // Ceperley-Adler P depc_drho = dFec_rsgt1_drho(rs, beta1p, beta2p, gammap, depc_drs); } else { // rs < 1. // Ceperley U with A_u and B_u // deuc_drho = dFec_rslt1_drho(rs, 0.0311, -0.048, 0.0014, -0.0108, deuc_drs); // Ceperley P with A_p and B_p // depc_drho = dFec_rslt1_drho(rs, 0.01555, -0.0269, 0.0001, -0.0046, depc_drs); // Ceperley-Adler U with A_u and B_u deuc_drho = dFec_rslt1_drho(rs, Au, Bu, Cu, Du, deuc_drs); // Ceperley-Adler P with A_p and B_p depc_drho = dFec_rslt1_drho(rs, Ap, Bp, Cp, Dp, depc_drs); } double dfzeta_dzeta = 4./3.*( pow((1.+zeta), (1./3.)) - pow((1.-zeta), (1./3.)) ) / (pow(2., (4./3.)) - 2.); decrs = deuc_drs + fzeta*(depc_drs - deuc_drs); deczeta = dfzeta_dzeta*(epc - euc); od.df_drho_a = deuc_drho + fzeta*(depc_drho - deuc_drho) + (epc - euc)*(1.-zeta)*dfzeta_dzeta; od.df_drho_b = deuc_drho + fzeta*(depc_drho - deuc_drho) + (epc - euc)*(-1.-zeta)*dfzeta_dzeta; } } ///////////////////////////////////////////////////////////////////////////// // VWNLCFunctional // Coded by Matt Leininger static ClassDesc VWNLCFunctional_cd( typeid(VWNLCFunctional),"VWNLCFunctional",1,"public LSDACFunctional", 0, create, create); VWNLCFunctional::VWNLCFunctional(StateIn& s): SavableState(s), LSDACFunctional(s) { s.get(Ap_); s.get(Af_); s.get(A_alpha_); s.get(x0p_mc_); s.get(bp_mc_); s.get(cp_mc_); s.get(x0f_mc_); s.get(bf_mc_); s.get(cf_mc_); s.get(x0_alpha_mc_); s.get(b_alpha_mc_); s.get(c_alpha_mc_); s.get(x0p_rpa_); s.get(bp_rpa_); s.get(cp_rpa_); s.get(x0f_rpa_); s.get(bf_rpa_); s.get(cf_rpa_); s.get(x0_alpha_rpa_); s.get(b_alpha_rpa_); s.get(c_alpha_rpa_); } VWNLCFunctional::VWNLCFunctional() { init_constants(); } VWNLCFunctional::~VWNLCFunctional() { } VWNLCFunctional::VWNLCFunctional(const Ref& keyval): LSDACFunctional(keyval) { init_constants(); Ap_ = keyval->doublevalue("Ap", KeyValValuedouble(Ap_)); Af_ = keyval->doublevalue("Af", KeyValValuedouble(Af_)); A_alpha_ = keyval->doublevalue("A_alpha", KeyValValuedouble(A_alpha_)); x0p_mc_ = keyval->doublevalue("x0p_mc", KeyValValuedouble(x0p_mc_)); bp_mc_ = keyval->doublevalue("bp_mc", KeyValValuedouble(bp_mc_)); cp_mc_ = keyval->doublevalue("cp_mc", KeyValValuedouble(cp_mc_)); x0f_mc_ = keyval->doublevalue("x0f_mc", KeyValValuedouble(x0f_mc_)); bf_mc_ = keyval->doublevalue("bf_mc", KeyValValuedouble(bf_mc_)); cf_mc_ = keyval->doublevalue("cf_mc", KeyValValuedouble(cf_mc_)); x0_alpha_mc_ = keyval->doublevalue("x0_alpha_mc", KeyValValuedouble(x0_alpha_mc_)); b_alpha_mc_ = keyval->doublevalue("b_alpha_mc", KeyValValuedouble(b_alpha_mc_)); c_alpha_mc_ = keyval->doublevalue("c_alpha_mc", KeyValValuedouble(c_alpha_mc_)); x0p_rpa_ = keyval->doublevalue("x0p_rpa", KeyValValuedouble(x0p_rpa_)); bp_rpa_ = keyval->doublevalue("bp_rpa", KeyValValuedouble(bp_rpa_)); cp_rpa_ = keyval->doublevalue("cp_rpa", KeyValValuedouble(cp_rpa_)); x0f_rpa_ = keyval->doublevalue("x0f_rpa", KeyValValuedouble(x0f_rpa_)); bf_rpa_ = keyval->doublevalue("bf_rpa", KeyValValuedouble(bf_rpa_)); cf_rpa_ = keyval->doublevalue("cf_rpa", KeyValValuedouble(cf_rpa_)); x0_alpha_rpa_ = keyval->doublevalue("x0_alpha_rpa", KeyValValuedouble(x0_alpha_rpa_)); b_alpha_rpa_ = keyval->doublevalue("b_alpha_rpa", KeyValValuedouble(b_alpha_rpa_)); c_alpha_rpa_ = keyval->doublevalue("c_alpha_rpa", KeyValValuedouble(c_alpha_rpa_)); } void VWNLCFunctional::save_data_state(StateOut& s) { LSDACFunctional::save_data_state(s); s.put(Ap_); s.put(Af_); s.put(A_alpha_); s.put(x0p_mc_); s.put(bp_mc_); s.put(cp_mc_); s.put(x0f_mc_); s.put(bf_mc_); s.put(cf_mc_); s.put(x0_alpha_mc_); s.put(b_alpha_mc_); s.put(c_alpha_mc_); s.put(x0p_rpa_); s.put(bp_rpa_); s.put(cp_rpa_); s.put(x0f_rpa_); s.put(bf_rpa_); s.put(cf_rpa_); s.put(x0_alpha_rpa_); s.put(b_alpha_rpa_); s.put(c_alpha_rpa_); } void VWNLCFunctional::init_constants() { Ap_ = 0.0310907; Af_ = 0.01554535; A_alpha_ = -1./(6.*M_PI*M_PI); x0p_mc_ = -0.10498; bp_mc_ = 3.72744; cp_mc_ = 12.9352; x0f_mc_ = -0.32500; bf_mc_ = 7.06042; cf_mc_ = 18.0578; x0_alpha_mc_ = -0.00475840; b_alpha_mc_ = 1.13107; c_alpha_mc_ = 13.0045; x0p_rpa_ = -0.409286; bp_rpa_ = 13.0720; cp_rpa_ = 42.7198; x0f_rpa_ = -0.743294; bf_rpa_ = 20.1231; cf_rpa_ = 101.578; x0_alpha_rpa_ = -0.228344; b_alpha_rpa_ = 1.06835; c_alpha_rpa_ = 11.4813; } double VWNLCFunctional::F(double x, double A, double x0, double b, double c) { double x2 = x*x; double x02 = x0*x0; double Xx = x2 + b*x + c; double Xx0 = x02 + b*x0 + c; double Q = sqrt(4.*c-b*b); double res = A * ( log(x2/Xx) + 2.*b/Q * atan(Q/(2.*x+b)) - b*x0/Xx0 * ( log((x-x0)*(x-x0)/Xx) + 2.*(b+2.*x0)/Q * atan(Q/(2.*x+b)) ) ); return res; } double VWNLCFunctional::dFdr_s(double x, double A, double x0, double b, double c) { double x2 = x*x; double x02 = x0*x0; double Xx = x2 + b*x +c; double Xx0 = x02 + b*x0 + c; double Q = sqrt(4.*c-b*b); double res = A * ( 1./x2 - 1./Xx - b/(2.*Xx*x) + ((x0*(2.*x0+b))/Xx0 - 1) * (2.*b)/(x*(Q*Q+(2.*x+b)*(2.*x+b))) - (b*x0)/(x*(x-x0)*Xx0) + (b*x0*(1+(b/(2.*x))))/(Xx0*Xx) ); return res; } void VWNLCFunctional::point_lc(const PointInputData &id, PointOutputData &od, double &ec_local, double &decrs, double &deczeta) { } ///////////////////////////////////////////////////////////////////////////// // VWN1LCFunctional // Coded by Matt Leininger static ClassDesc VWN1LCFunctional_cd( typeid(VWN1LCFunctional),"VWN1LCFunctional",1,"public LSDACFunctional", 0, create, create); VWN1LCFunctional::VWN1LCFunctional(StateIn& s): SavableState(s), VWNLCFunctional(s) { s.get(x0p_); s.get(bp_); s.get(cp_); s.get(x0f_); s.get(bf_); s.get(cf_); } VWN1LCFunctional::VWN1LCFunctional() { x0p_ = x0p_mc_; bp_ = bp_mc_; cp_ = cp_mc_; x0f_ = x0f_mc_; bf_ = bf_mc_; cf_ = cf_mc_; } VWN1LCFunctional::VWN1LCFunctional(int use_rpa) { if (use_rpa) { x0p_ = x0p_rpa_; bp_ = bp_rpa_; cp_ = cp_rpa_; x0f_ = x0f_rpa_; bf_ = bf_rpa_; cf_ = cf_rpa_; } else { x0p_ = x0p_mc_; bp_ = bp_mc_; cp_ = cp_mc_; x0f_ = x0f_mc_; bf_ = bf_mc_; cf_ = cf_mc_; } } VWN1LCFunctional::VWN1LCFunctional(const Ref& keyval): VWNLCFunctional(keyval) { int vwn1rpa = keyval->booleanvalue("rpa", KeyValValueboolean(0)); if (vwn1rpa) { x0p_ = x0p_rpa_; bp_ = bp_rpa_; cp_ = cp_rpa_; x0f_ = x0f_rpa_; bf_ = bf_rpa_; cf_ = cf_rpa_; } else { x0p_ = x0p_mc_; bp_ = bp_mc_; cp_ = cp_mc_; x0f_ = x0f_mc_; bf_ = bf_mc_; cf_ = cf_mc_; } x0p_ = keyval->doublevalue("x0p", KeyValValuedouble(x0p_)); bp_ = keyval->doublevalue("bp", KeyValValuedouble(bp_)); cp_ = keyval->doublevalue("cp", KeyValValuedouble(cp_)); x0f_ = keyval->doublevalue("x0f", KeyValValuedouble(x0f_)); bf_ = keyval->doublevalue("bf", KeyValValuedouble(bf_)); cf_ = keyval->doublevalue("cf", KeyValValuedouble(cf_)); } VWN1LCFunctional::~VWN1LCFunctional() { } void VWN1LCFunctional::save_data_state(StateOut& s) { VWNLCFunctional::save_data_state(s); s.put(x0p_); s.put(bp_); s.put(cp_); s.put(x0f_); s.put(bf_); s.put(cf_); } // Based on the VWN1 functional in Vosko, Wilk, and Nusair, Can. J. Phys. // 58, 1200, (1980). void VWN1LCFunctional::point_lc(const PointInputData &id, PointOutputData &od, double &ec_local, double &decrs, double &deczeta) { od.zero(); double four_thirds = 4./3.; double one_third = 1./3.; double two_thirds = 2./3.; double sixth = 1./6.; double rho = id.a.rho + id.b.rho; double zeta = (id.a.rho - id.b.rho)/rho; double x = pow(3./(4.*M_PI*rho), sixth); double rs = x*x; double epc = F(x, Ap_, x0p_, bp_, cp_); double efc = F(x, Af_, x0f_, bf_, cf_); const double fpp0 = 4./9. * 1./(pow(2., (1./3.)) - 1.); double f = 9./8.*fpp0*(pow(1.+zeta, four_thirds)+pow(1.-zeta, four_thirds)-2.); double delta_ec = f * (efc - epc); double ec = epc + delta_ec; ec_local = ec; od.energy = ec * rho; if (compute_potential_) { if (!spin_polarized_) { double depc_dr_s0 = dFdr_s(x, Ap_, x0p_, bp_, cp_); double dec_dr_s = depc_dr_s0; od.df_drho_a = od.df_drho_b = ec - (rs/3.)*dec_dr_s; decrs = dec_dr_s; deczeta = 0.; } else { double depc_dr_s0 = dFdr_s(x, Ap_, x0p_, bp_, cp_); double defc_dr_s1 = dFdr_s(x, Af_, x0f_, bf_, cf_); double dec_dr_s = depc_dr_s0 + f * (defc_dr_s1 - depc_dr_s0); double fp = two_thirds * (pow((1+zeta),one_third) - pow((1-zeta),one_third))/(pow(2.,one_third)-1); // double dec_dzeta = depc_dr_s0 + fp * (efc - epc) + f * (defc_dr_s1 - depc_dr_s0); double dec_dzeta = fp * (efc - epc); od.df_drho_a = ec - (rs/3.)*dec_dr_s - (zeta-1)*dec_dzeta; od.df_drho_b = ec - (rs/3.)*dec_dr_s - (zeta+1)*dec_dzeta; decrs = dec_dr_s; deczeta = dec_dzeta; } } } ///////////////////////////////////////////////////////////////////////////// // VWN2LCFunctional // Coded by Matt Leininger static ClassDesc VWN2LCFunctional_cd( typeid(VWN2LCFunctional),"VWN2LCFunctional",1,"public VWNLCFunctional", 0, create, create); VWN2LCFunctional::VWN2LCFunctional(StateIn& s): SavableState(s), VWNLCFunctional(s) { } VWN2LCFunctional::VWN2LCFunctional() { } VWN2LCFunctional::VWN2LCFunctional(const Ref& keyval): VWNLCFunctional(keyval) { } VWN2LCFunctional::~VWN2LCFunctional() { } void VWN2LCFunctional::save_data_state(StateOut& s) { VWNLCFunctional::save_data_state(s); } void VWN2LCFunctional::point_lc(const PointInputData &id, PointOutputData &od, double &ec_local, double &decrs, double &deczeta) { od.zero(); const double fpp0 = 4./9. * 1./(pow(2., (1./3.)) - 1.); const double sixth = 1./6.; const double four_thirds = 4./3.; const double one_third = 1./3.; const double two_thirds = 2./3.; double rho = id.a.rho + id.b.rho; double zeta = (id.a.rho - id.b.rho)/rho; double x = pow(3./(4.*M_PI*rho), sixth); double rs = x*x; // Monte Carlo fitting parameters double epc_mc = F(x, Ap_, x0p_mc_, bp_mc_, cp_mc_); double efc_mc = F(x, Af_, x0f_mc_, bf_mc_, cf_mc_); //double alphac_mc = F(x, A_alpha_, x0_alpha_mc_, b_alpha_mc_, c_alpha_mc_); // RPA fitting parameters double epc_rpa = F(x, Ap_, x0p_rpa_, bp_rpa_, cp_rpa_); double efc_rpa = F(x, Af_, x0f_rpa_, bf_rpa_, cf_rpa_); double alphac_rpa = F(x, A_alpha_, x0_alpha_rpa_, b_alpha_rpa_, c_alpha_rpa_); double f = 9./8.*fpp0*(pow(1.+zeta, four_thirds)+pow(1.-zeta, four_thirds)-2.); double zeta2 = zeta*zeta; double zeta4 = zeta2*zeta2; double delta_e_rpa = efc_rpa - epc_rpa; double delta_e_mc = efc_mc - epc_mc; double beta = (fpp0*delta_e_rpa / alphac_rpa) - 1.; double delta_erpa_rszeta = alphac_rpa * f / fpp0 * (1. + beta * zeta4); double delta_ec = delta_erpa_rszeta + f*(delta_e_mc - delta_e_rpa); double ec = epc_mc + delta_ec; od.energy = ec * rho; ec_local = ec; if (compute_potential_) { //double zeta3 = zeta2*zeta; // Monte Carlo fitting parameters double depc_dr_s0_mc = dFdr_s(x, Ap_,x0p_mc_, bp_mc_, cp_mc_); double defc_dr_s1_mc = dFdr_s(x, Af_, x0f_mc_, bf_mc_, cf_mc_); double dalphac_dr_s_mc = dFdr_s(x, A_alpha_, x0_alpha_mc_, b_alpha_mc_, c_alpha_mc_); // RPA fitting parameters double depc_dr_s0_rpa = dFdr_s(x, Ap_, x0p_rpa_, bp_rpa_, cp_rpa_); double defc_dr_s1_rpa = dFdr_s(x, Af_, x0f_rpa_, bf_rpa_, cf_rpa_); double dalphac_dr_s_rpa = dFdr_s(x, A_alpha_, x0_alpha_rpa_, b_alpha_rpa_, c_alpha_rpa_); double fp = two_thirds * (pow((1+zeta),one_third) - pow((1-zeta),one_third))/(pow(2.,one_third)-1); // RPA fitting parameters double ddelta_e_rpa = defc_dr_s1_rpa - depc_dr_s0_rpa; double ddeltae_rpa_dr_s = f / fpp0 * (1 - zeta4)* dalphac_dr_s_rpa + f * zeta4 * ddelta_e_rpa; double ddeltae_rpa_dzeta = alphac_rpa / fpp0 * ( fp * (1.-zeta4) - 4.* f * zeta*zeta2) + delta_e_rpa * ( fp*zeta4 + 4.*f*zeta*zeta2); // Monte Carlo fitting parameters double ddelta_e_mc = defc_dr_s1_rpa - depc_dr_s0_mc; // double dec_dr_s_mc = depc_dr_s0*(1 - f*zeta4) + defc_dr_s1 * f * zeta4 // + dalphac_dr_s * f / fpp0 * (1 - zeta4); // double dec_dzeta_mc = 4.* zeta3 * f * (efc_mc - epc_mc - (alphac_mc/fpp0)) // + fp * (zeta4 * (efc_mc - epc_mc) + (1-zeta4)*(alphac_mc/fpp0)); double dec_dr_s = depc_dr_s0_mc + ddeltae_rpa_dr_s + f * (ddelta_e_mc - ddelta_e_rpa); double dec_dzeta = ddeltae_rpa_dzeta + fp * (delta_e_mc - delta_e_rpa); od.df_drho_a = ec - (rs/3.)*dec_dr_s - (zeta-1)*dec_dzeta; od.df_drho_b = ec - (rs/3.)*dec_dr_s - (zeta+1)*dec_dzeta; decrs = dec_dr_s; deczeta = dec_dzeta; } } ///////////////////////////////////////////////////////////////////////////// // VWN3LCFunctional // Coded by Matt Leininger static ClassDesc VWN3LCFunctional_cd( typeid(VWN3LCFunctional),"VWN3LCFunctional",1,"public VWNLCFunctional", 0, create, create); VWN3LCFunctional::VWN3LCFunctional(StateIn& s): SavableState(s), VWNLCFunctional(s) { s.get(monte_carlo_prefactor_); s.get(monte_carlo_e0_); } VWN3LCFunctional::VWN3LCFunctional(int mcp, int mce0) { monte_carlo_prefactor_ = mcp; monte_carlo_e0_ = mce0; } VWN3LCFunctional::VWN3LCFunctional(const Ref& keyval): VWNLCFunctional(keyval) { monte_carlo_prefactor_ = keyval->booleanvalue("monte_carlo_prefactor", KeyValValueboolean(1)); monte_carlo_e0_ = keyval->booleanvalue("monte_carlo_e0", KeyValValueboolean(1)); } VWN3LCFunctional::~VWN3LCFunctional() { } void VWN3LCFunctional::save_data_state(StateOut& s) { VWNLCFunctional::save_data_state(s); s.put(monte_carlo_prefactor_); s.put(monte_carlo_e0_); } // based on the equations given on a NIST WWW site void VWN3LCFunctional::point_lc(const PointInputData &id, PointOutputData &od, double &ec_local, double &decrs, double &deczeta) { od.zero(); const double fpp0 = 4./9. * 1./(pow(2., (1./3.)) - 1.); const double sixth = 1./6.; const double four_thirds = 4./3.; const double one_third = 1./3.; const double two_thirds = 2./3.; double rho = id.a.rho + id.b.rho; double zeta = (id.a.rho - id.b.rho)/rho; double x = pow(3./(4.*M_PI*rho), sixth); double rs = x*x; // Monte Carlo fitting parameters double epc0_mc = F(x, Ap_, x0p_mc_, bp_mc_, cp_mc_); double efc1_mc = F(x, Af_, x0f_mc_, bf_mc_, cf_mc_); // double alphac_mc = F(x, A_alpha_, x0_alpha_mc_, b_alpha_mc_, c_alpha_mc_); // RPA fitting parameters double epc0_rpa = F(x, Ap_, x0p_rpa_, bp_rpa_, cp_rpa_); double efc1_rpa = F(x, Af_, x0f_rpa_, bf_rpa_, cf_rpa_); double alphac_rpa = F(x, A_alpha_, x0_alpha_rpa_, b_alpha_rpa_, c_alpha_rpa_); double f = 9./8.*fpp0*( pow(1.+zeta, four_thirds) + pow(1.-zeta, four_thirds) - 2.); double zeta2 = zeta*zeta; double zeta4 = zeta2*zeta2; double delta_e_rpa = efc1_rpa - epc0_rpa; double delta_e_mc = efc1_mc - epc0_mc; double delta_erpa_rszeta = alphac_rpa * f / fpp0 * (1.-zeta4) + f * zeta4 * delta_e_rpa; double delta_ec; if (!monte_carlo_prefactor_) delta_ec = delta_erpa_rszeta; else delta_ec = delta_e_mc/delta_e_rpa * delta_erpa_rszeta; double ec; if (monte_carlo_e0_) ec = epc0_mc; else ec = epc0_rpa; ec += delta_ec; od.energy = ec * rho; ec_local = ec; if (compute_potential_) { // Monte Carlo fitting parameters double depc_dr_s0_mc = dFdr_s(x, Ap_, x0p_mc_, bp_mc_, cp_mc_); double defc_dr_s1_mc = dFdr_s(x, Af_, x0f_mc_, bf_mc_, cf_mc_); // double dalphac_dr_s_mc = dFdr_s(x, A_alpha_, x0_alpha_mc_, b_alpha_mc_, c_alpha_mc_); // RPA fitting parameters double depc_dr_s0_rpa = dFdr_s(x, Ap_, x0p_rpa_, bp_rpa_, cp_rpa_); double defc_dr_s1_rpa = dFdr_s(x, Af_, x0f_rpa_, bf_rpa_, cf_rpa_); double dalphac_dr_s_rpa = dFdr_s(x, A_alpha_, x0_alpha_rpa_, b_alpha_rpa_, c_alpha_rpa_); double fp = two_thirds * (pow((1+zeta),one_third) - pow((1-zeta),one_third))/(pow(2.,one_third)-1); // RPA fitting parameters double ddelta_e_rpa = defc_dr_s1_rpa - depc_dr_s0_rpa; double ddeltae_rpa_dr_s = f / fpp0 * (1 - zeta4)* dalphac_dr_s_rpa + f * zeta4 * ddelta_e_rpa; double ddeltae_rpa_dzeta = alphac_rpa / fpp0 * ( fp * (1.-zeta4) - 4.* f * zeta*zeta2) + delta_e_rpa * ( fp*zeta4 + 4.*f*zeta*zeta2 ); // Monte Carlo fitting parameters double ddelta_e_mc = defc_dr_s1_mc - depc_dr_s0_mc; double dec_dzeta, dec_dr_s; if (!monte_carlo_prefactor_) { dec_dzeta = ddeltae_rpa_dzeta; if (monte_carlo_e0_) dec_dr_s = depc_dr_s0_mc; else dec_dr_s = depc_dr_s0_rpa; dec_dr_s += ddeltae_rpa_dr_s; } else { dec_dzeta = delta_e_mc / delta_e_rpa * ddeltae_rpa_dzeta; if (monte_carlo_e0_) dec_dr_s = depc_dr_s0_mc; else dec_dr_s = depc_dr_s0_rpa; dec_dr_s += delta_erpa_rszeta/delta_e_rpa * ddelta_e_mc + delta_e_mc/delta_e_rpa * ddeltae_rpa_dr_s - delta_erpa_rszeta*delta_e_mc/(delta_e_rpa*delta_e_rpa) * ddelta_e_rpa; } od.df_drho_a = ec - (rs/3.)*dec_dr_s - (zeta-1)*dec_dzeta; od.df_drho_b = ec - (rs/3.)*dec_dr_s - (zeta+1)*dec_dzeta; decrs = dec_dr_s; deczeta = dec_dzeta; } } ///////////////////////////////////////////////////////////////////////////// // VWN4LCFunctional // Coded by Matt Leininger static ClassDesc VWN4LCFunctional_cd( typeid(VWN4LCFunctional),"VWN4LCFunctional",1,"public VWNLCFunctional", 0, create, create); VWN4LCFunctional::VWN4LCFunctional(StateIn& s): SavableState(s), VWNLCFunctional(s) { s.get(monte_carlo_prefactor_); } VWN4LCFunctional::VWN4LCFunctional() { monte_carlo_prefactor_ = 0; } VWN4LCFunctional::VWN4LCFunctional(const Ref& keyval): VWNLCFunctional(keyval) { monte_carlo_prefactor_ = keyval->booleanvalue("monte_carlo_prefactor", KeyValValueboolean(0)); } VWN4LCFunctional::~VWN4LCFunctional() { } void VWN4LCFunctional::save_data_state(StateOut& s) { VWNLCFunctional::save_data_state(s); s.put(monte_carlo_prefactor_); } // based on the equations given on a NIST WWW site void VWN4LCFunctional::point_lc(const PointInputData &id, PointOutputData &od, double &ec_local, double &decrs, double &deczeta) { od.zero(); const double fpp0 = 4./9. * 1./(pow(2., (1./3.)) - 1.); const double sixth = 1./6.; const double four_thirds = 4./3.; const double one_third = 1./3.; const double two_thirds = 2./3.; double rho = id.a.rho + id.b.rho; double zeta = (id.a.rho - id.b.rho)/rho; double x = pow(3./(4.*M_PI*rho), sixth); double rs = x*x; // Monte Carlo fitting parameters double epc_mc = F(x, Ap_, x0p_mc_, bp_mc_, cp_mc_); double efc_mc = F(x, Af_, x0f_mc_, bf_mc_, cf_mc_); // double alphac_mc = F(x, A_alpha_, x0_alpha_mc_, b_alpha_mc_, c_alpha_mc_); // RPA fitting parameters double epc_rpa = F(x, Ap_, x0p_rpa_, bp_rpa_, cp_rpa_); double efc_rpa = F(x, Af_, x0f_rpa_, bf_rpa_, cf_rpa_); double alphac_rpa = F(x, A_alpha_, x0_alpha_rpa_, b_alpha_rpa_, c_alpha_rpa_); double f = 9./8.*fpp0*(pow(1.+zeta, four_thirds)+pow(1.-zeta, four_thirds)-2.); double zeta2 = zeta*zeta; double zeta4 = zeta2*zeta2; double delta_e_rpa = efc_rpa - epc_rpa; double delta_e_mc = efc_mc - epc_mc; // double beta = fpp0 * delta_e_mc / alphac_rpa - 1.; // double delta_erpa_rszeta = alphac_rpa * f / fpp0 * (1. + beta * zeta4); // use delta_e_rpa here instead of delta_e_mc to get VWN3 double delta_erpa_rszeta = alphac_rpa * f / fpp0 * (1. - zeta4) + f * delta_e_mc * zeta4; double delta_ec; if (!monte_carlo_prefactor_) delta_ec = delta_erpa_rszeta; else delta_ec = delta_e_mc/delta_e_rpa * delta_erpa_rszeta; // double ec = epc_rpa + delta_ec; double ec = epc_mc + delta_ec; od.energy = ec * rho; ec_local = ec; if (compute_potential_) { double zeta3 = zeta2*zeta; // Monte Carlo fitting parameters double depc_dr_s0_mc = dFdr_s(x, Ap_, x0p_mc_, bp_mc_, cp_mc_); double defc_dr_s1_mc = dFdr_s(x, Af_, x0f_mc_, bf_mc_, cf_mc_); // double dalphac_dr_s_mc = dFdr_s(x, A_alpha_, x0_alpha_mc_, b_alpha_mc_, c_alpha_mc_); // RPA fitting parameters double depc_dr_s0_rpa = dFdr_s(x, Ap_, x0p_rpa_, bp_rpa_, cp_rpa_); double defc_dr_s1_rpa = dFdr_s(x, Af_, x0f_rpa_, bf_rpa_, cf_rpa_); double dalphac_dr_s_rpa = dFdr_s(x, A_alpha_, x0_alpha_rpa_, b_alpha_rpa_, c_alpha_rpa_); double fp = two_thirds * (pow((1+zeta),one_third) - pow((1-zeta),one_third))/(pow(2.,one_third)-1); double ddelta_e_rpa = defc_dr_s1_rpa - depc_dr_s0_rpa; double ddelta_e_mc = defc_dr_s1_mc - depc_dr_s0_mc; // use ddelta_e_rpa here instead of ddelta_e_mc to get VWN3 double ddeltae_rpa_dr_s = f / fpp0 * (1 - zeta4)* dalphac_dr_s_rpa + f * zeta4 * ddelta_e_mc; // use ddelta_e_rpa here instead of ddelta_e_mc to get VWN3 double ddeltae_rpa_dzeta = alphac_rpa / fpp0 * ( fp * (1.-zeta4) - 4.* f * zeta3) + delta_e_mc * ( fp*zeta4 + 4.*f*zeta3); double dec_dzeta, dec_dr_s; if (!monte_carlo_prefactor_) { // dec_dr_s = depc_dr_s0_rpa + ddeltae_rpa_dr_s; dec_dr_s = depc_dr_s0_mc + ddeltae_rpa_dr_s; dec_dzeta = ddeltae_rpa_dzeta; } else { dec_dr_s = depc_dr_s0_rpa + delta_erpa_rszeta/delta_e_rpa * ddelta_e_mc + delta_e_mc/delta_e_rpa * ddeltae_rpa_dr_s - delta_erpa_rszeta*delta_e_mc/(delta_e_rpa*delta_e_rpa)* ddelta_e_rpa; dec_dzeta = delta_e_mc / delta_e_rpa * ddeltae_rpa_dzeta; } od.df_drho_a = ec - (rs/3.)*dec_dr_s - (zeta-1.)*dec_dzeta; od.df_drho_b = ec - (rs/3.)*dec_dr_s - (zeta+1.)*dec_dzeta; decrs = dec_dr_s; deczeta = dec_dzeta; } } ///////////////////////////////////////////////////////////////////////////// // VWN5LCFunctional // Coded by Matt Leininger static ClassDesc VWN5LCFunctional_cd( typeid(VWN5LCFunctional),"VWN5LCFunctional",1,"public VWNLCFunctional", 0, create, create); VWN5LCFunctional::VWN5LCFunctional(StateIn& s): SavableState(s), VWNLCFunctional(s) { } VWN5LCFunctional::VWN5LCFunctional() { } VWN5LCFunctional::VWN5LCFunctional(const Ref& keyval): VWNLCFunctional(keyval) { } VWN5LCFunctional::~VWN5LCFunctional() { } void VWN5LCFunctional::save_data_state(StateOut& s) { VWNLCFunctional::save_data_state(s); } // based on the equations given on a NIST WWW site // based on the VWN5 functional in Vosko, Wilk, and Nusair, Can. J. Phys. // 58, 1200, (1980). and Perdew and Wang, Phys. Rev. B, 45, 13244, (1992). void VWN5LCFunctional::point_lc(const PointInputData &id, PointOutputData &od, double &ec_local, double &decrs, double &deczeta) { od.zero(); const double fpp0 = 4./9. * 1./(pow(2., (1./3.)) - 1.); const double sixth = 1./6.; const double four_thirds = 4./3.; const double one_third = 1./3.; const double two_thirds = 2./3.; double rho = id.a.rho + id.b.rho; double zeta = (id.a.rho - id.b.rho)/rho; double x = pow(3./(4.*M_PI*rho), sixth); double rs = x*x; double epc = F(x, Ap_, x0p_mc_, bp_mc_, cp_mc_); double efc = F(x, Af_, x0f_mc_, bf_mc_, cf_mc_); double alphac = F(x, A_alpha_, x0_alpha_mc_, b_alpha_mc_, c_alpha_mc_); double f = 9./8.*fpp0*(pow(1.+zeta, four_thirds)+pow(1.-zeta, four_thirds)-2.); double zeta2 = zeta*zeta; double zeta4 = zeta2*zeta2; double beta = fpp0 * (efc - epc) / alphac - 1.; double delta_ec = alphac * f / fpp0 * (1. + beta * zeta4); double ec = epc + delta_ec; ec_local = ec; od.energy = ec * rho; if (compute_potential_) { if (!spin_polarized_) { double depc_dr_s0 = dFdr_s(x, Ap_, x0p_mc_, bp_mc_, cp_mc_); double dec_dr_s = depc_dr_s0; od.df_drho_a = od.df_drho_b = ec - (rs/3.)*dec_dr_s; decrs = dec_dr_s; deczeta = 0.; } else { double zeta3 = zeta2*zeta; double depc_dr_s0 = dFdr_s(x, Ap_, x0p_mc_, bp_mc_, cp_mc_); double defc_dr_s1 = dFdr_s(x, Af_, x0f_mc_, bf_mc_, cf_mc_); double dalphac_dr_s = dFdr_s(x, A_alpha_, x0_alpha_mc_, b_alpha_mc_, c_alpha_mc_); double dec_dr_s = depc_dr_s0*(1 - f*zeta4) + defc_dr_s1 * f * zeta4 + dalphac_dr_s * f / fpp0 * (1 - zeta4); double fp = two_thirds * (pow((1+zeta),one_third) - pow((1-zeta),one_third))/(pow(2.,one_third)-1); double dec_dzeta = 4.* zeta3 * f * (efc - epc - (alphac/fpp0)) + fp * (zeta4 * (efc - epc) + (1-zeta4)*(alphac/fpp0)); od.df_drho_a = ec - (rs/3.)*dec_dr_s - (zeta-1)*dec_dzeta; od.df_drho_b = ec - (rs/3.)*dec_dr_s - (zeta+1)*dec_dzeta; decrs = dec_dr_s; deczeta = dec_dzeta; } } } ///////////////////////////////////////////////////////////////////////////// // XalphaFunctional static ClassDesc XalphaFunctional_cd( typeid(XalphaFunctional),"XalphaFunctional",1,"public DenFunctional", 0, create, create); XalphaFunctional::XalphaFunctional(StateIn& s): SavableState(s), DenFunctional(s) { s.get(alpha_); factor_ = alpha_ * 2.25 * pow(3.0/(4.*M_PI), 1.0/3.0); } XalphaFunctional::XalphaFunctional() { alpha_ = 0.70; factor_ = alpha_ * 2.25 * pow(3.0/(4.*M_PI), 1.0/3.0); } XalphaFunctional::XalphaFunctional(const Ref& keyval): DenFunctional(keyval) { alpha_ = keyval->doublevalue("alpha", KeyValValuedouble(0.70)); factor_ = alpha_ * 2.25 * pow(3.0/(4.*M_PI), 1.0/3.0); } XalphaFunctional::~XalphaFunctional() { } void XalphaFunctional::save_data_state(StateOut& s) { DenFunctional::save_data_state(s); s.put(alpha_); } void XalphaFunctional::point(const PointInputData &id, PointOutputData &od) { od.zero(); const double four_thirds = 4./3.; if (!spin_polarized_) { od.energy = - 2.0 * factor_ * id.a.rho * id.a.rho_13; if (compute_potential_) { od.df_drho_a = -four_thirds * factor_ * id.a.rho_13; od.df_drho_b = od.df_drho_a; } } else { double rhoa43 = id.a.rho * id.a.rho_13; double rhob43 = id.b.rho * id.b.rho_13; od.energy = - factor_ * (rhoa43 + rhob43); if (compute_potential_) { od.df_drho_a = -four_thirds * factor_ * id.a.rho_13; od.df_drho_b = -four_thirds * factor_ * id.b.rho_13; } } } void XalphaFunctional::print(ostream& o) const { o << indent << scprintf("XalphaFunctional: alpha = %12.8f", alpha_) << endl; } ///////////////////////////////////////////////////////////////////////////// // Becke88XFunctional static ClassDesc Becke88XFunctional_cd( typeid(Becke88XFunctional),"Becke88XFunctional",1,"public DenFunctional", 0, create, create); Becke88XFunctional::Becke88XFunctional(StateIn& s): SavableState(s), DenFunctional(s) { s.get(beta_); beta6_ = 6. * beta_; } Becke88XFunctional::Becke88XFunctional() { beta_ = 0.0042; beta6_ = 6. * beta_; } Becke88XFunctional::Becke88XFunctional(const Ref& keyval): DenFunctional(keyval) { beta_ = keyval->doublevalue("beta", KeyValValuedouble(0.0042)); beta6_ = 6. * beta_; } Becke88XFunctional::~Becke88XFunctional() { } void Becke88XFunctional::save_data_state(StateOut& s) { DenFunctional::save_data_state(s); s.put(beta_); } int Becke88XFunctional::need_density_gradient() { return 1; } // Becke's exchange // From: C.W. Murray et al. Mol. Phys. Vol 78 pp 997-1014 (1993) // originally coded by Mike Colvin void Becke88XFunctional::point(const PointInputData &id, PointOutputData &od) { od.zero(); // Preset terms from Murray's paper const double beta = beta_; const double beta6 = beta6_; // const double beta6=0.0252; // Use simplified formula double rho_a_13 = pow(id.a.rho,(1./3.)); double rho_a_43 = id.a.rho*rho_a_13; double xa, xa2, ga_denom, ga_denom2; if (id.a.rho > MIN_DENSITY) { xa = sqrt(id.a.gamma)/rho_a_43; xa2 = xa*xa; ga_denom = 1/(1.+beta6*xa*asinh(xa)); ga_denom2 = ga_denom*ga_denom; } else { xa = xa2 = 0.; ga_denom = ga_denom2 = 1.; } double Fa = sqrt(1.+xa2); double Ha = 1. - 6.*beta*xa2/Fa; double ex; if (id.a.rho > MIN_DENSITY) ex = -rho_a_43*beta*xa2*ga_denom; else ex = 0.; if (compute_potential_) { if (id.a.rho > MIN_DENSITY) { od.df_drho_a = 4./3. * beta * rho_a_13 * xa2 * ga_denom2 * Ha; od.df_dgamma_aa = -beta * ga_denom / (2.*rho_a_43) * (1. + ga_denom*Ha); } else od.df_drho_a = od.df_dgamma_aa = 0.; od.df_drho_b=od.df_drho_a; od.df_dgamma_bb=od.df_dgamma_aa; } if (spin_polarized_) { double rho_b_13 = pow(id.b.rho,(1./3.)); double rho_b_43 = id.b.rho*rho_b_13; double xb, xb2, gb_denom, gb_denom2; if (id.b.rho > MIN_DENSITY) { xb = sqrt(id.b.gamma)/rho_b_43; xb2 = xb*xb; gb_denom = 1./(1.+beta6*xb*asinh(xb)); gb_denom2 = gb_denom*gb_denom; } else { xb = xb2 = 0.; gb_denom = gb_denom2 = 1.; } double Fb = sqrt(1.+xb2); double Hb = 1. - 6.*beta*xb2/Fb; ex += -rho_b_43*beta*xb2*gb_denom; if (compute_potential_) { if (id.b.rho > MIN_DENSITY) { od.df_drho_b = 4./3. * beta * rho_b_13 * xb2 * gb_denom2 * Hb; od.df_dgamma_bb = -beta / (2.*rho_b_43) * (gb_denom + gb_denom2*Hb); } else od.df_drho_b = od.df_dgamma_bb = 0.; } } else ex += ex; od.energy = ex; } ///////////////////////////////////////////////////////////////////////////// // LYPCFunctional // Coded by Matt Leininger static ClassDesc LYPCFunctional_cd( typeid(LYPCFunctional),"LYPCFunctional",1,"public DenFunctional", 0, create, create); LYPCFunctional::LYPCFunctional(StateIn& s): SavableState(s), DenFunctional(s) { s.get(a_); s.get(b_); s.get(c_); s.get(d_); } LYPCFunctional::LYPCFunctional() { init_constants(); } LYPCFunctional::LYPCFunctional(const Ref& keyval): DenFunctional(keyval) { init_constants(); a_ = keyval->doublevalue("a", KeyValValuedouble(a_)); b_ = keyval->doublevalue("b", KeyValValuedouble(b_)); c_ = keyval->doublevalue("c", KeyValValuedouble(c_)); d_ = keyval->doublevalue("d", KeyValValuedouble(d_)); } LYPCFunctional::~LYPCFunctional() { } void LYPCFunctional::save_data_state(StateOut& s) { DenFunctional::save_data_state(s); s.put(a_); s.put(b_); s.put(c_); s.put(d_); } void LYPCFunctional::init_constants() { a_ = 0.04918; b_ = 0.132; c_ = 0.2533; d_ = 0.349; } int LYPCFunctional::need_density_gradient() { return 1; } // Lee-Yang-Parr correlation // From: Burkhard Miehlich, et al. Chem Phys. Lett. Vol. 157 pp200-206 (1989) // Original LYP paper Phys. Rev. B Vol. 37 pp785-789 (1988) // originally coded by Mike Colvin // potential terms added by Matt Leininger void LYPCFunctional::point(const PointInputData &id, PointOutputData &od) { od.zero(); double ec; // Precalculate terms for efficiency double dens=id.a.rho+id.b.rho; double dens2=dens*dens; // double grad=id.a.gamma+id.b.gamma; // double grad=sqrt( pow(id.a.del_rho[0]+id.b.del_rho[0],2.) // + pow(id.a.del_rho[1]+id.b.del_rho[1],2.) // + pow(id.a.del_rho[2]+id.b.del_rho[2],2.) ); // double grad2=grad*grad; double dens1_3=pow(dens,-1./3.); // Precalculate terms defined in Miehlich's paper const double a = a_; const double b = b_; const double c = c_; const double d = d_; double omega=exp(-c*dens1_3)/(1.+d*dens1_3)*pow(dens,-11./3.); double delta=c*dens1_3+d*dens1_3/(1.+d*dens1_3); double cf=0.3*pow(3.* M_PI*M_PI,2./3.); double denom = 1.+d*dens1_3; double dens_a2=id.a.rho*id.a.rho; double dens_b2=id.b.rho*id.b.rho; double dens_ab=id.a.rho*id.b.rho; double grad_a2=id.a.gamma; double grad_b2=id.b.gamma; double grad_ab=id.gamma_ab; double eflyp_1 = -4.*a*dens_ab/(dens*denom); double intermediate_1 = pow(2.,2./3.)*144.*cf*(pow(id.a.rho,8./3.)+pow(id.b.rho,8./3.)) + (47.-7.*delta)*(grad_a2+grad_b2+2.*grad_ab)-(45.-delta)*(grad_a2+grad_b2) + 2.*(11.-delta)/dens*(id.a.rho*grad_a2+id.b.rho*grad_b2); double intermediate_2 = -4./3.*dens2*grad_ab - (dens_a2*grad_b2+dens_b2*grad_a2); double intermediate_3 = dens_ab/18.* intermediate_1 + intermediate_2; double eflyp_2 = -omega*a*b*intermediate_3; ec = eflyp_1 + eflyp_2; od.energy = ec; if (compute_potential_) { double dens4_3 = pow(dens,-4./3.); double expo = exp(-c*dens1_3); double ddelta_drho_a = 1./3* (d*d*dens4_3*dens1_3/(denom*denom) - delta/dens); double domega_drho_a = -1./3.*omega*dens4_3*(11./dens1_3 - c - d/denom); double df1_drho_a; df1_drho_a = -4.*a*id.b.rho/(dens*denom) * (id.a.rho/3.*d*dens4_3/denom + 1. - id.a.rho/dens); // if (id.a.rho > MIN_DENSITY) // df1_drho_a = -4.*a*dens_ab/(dens*denom) // * (1./3.*d*dens4_3/denom + 1/id.a.rho - 1./dens); // else df1_drho_a = 0.; double df2_drho_a = -domega_drho_a*a*b*intermediate_3 - omega*a*b*( id.b.rho/18.* intermediate_1 + dens_ab/18.*(144.*pow(2.,2./3.)*cf*8./3.*pow(id.a.rho,5./3.) + 2.*(11.-delta)*grad_a2/dens - 2./dens*ddelta_drho_a*(id.a.rho*grad_a2 + id.b.rho*grad_b2) - 2.*(11.-delta)/dens2*(id.a.rho*grad_a2 + id.b.rho*grad_b2) - 7.*ddelta_drho_a*(grad_a2+grad_b2+2.*grad_ab) + ddelta_drho_a*(grad_a2+grad_b2) ) - 8./3.*dens*grad_ab - 2.*id.a.rho*grad_b2 ); od.df_drho_a = df1_drho_a + df2_drho_a; od.df_dgamma_aa = -omega*a*b * (dens_ab/9.*(1.-3.*delta + id.a.rho*(11.-delta)/dens) - dens_b2); od.df_dgamma_ab = -omega*a*b*(dens_ab/9.*(47.-7.*delta) - 4./3.*dens2); od.df_drho_b = od.df_drho_a; od.df_dgamma_bb = od.df_dgamma_aa; if (spin_polarized_) { double ddelta_drho_b = ddelta_drho_a; double domega_drho_b = domega_drho_a; double df1_drho_b; df1_drho_b = -4.*a*id.a.rho/(dens*denom) * (id.b.rho/3.*d*dens4_3/denom + 1. - id.b.rho/dens); //if (id.b.rho > MIN_DENSITY) // df1_drho_b = -4.*a*dens_ab/(dens*denom) // * (1./3.*d*dens4_3/denom + 1./id.b.rho - 1./dens); //else df1_drho_b = 0.; double df2_drho_b = -domega_drho_b*a*b*intermediate_3 - omega*a*b*( id.a.rho/18.* intermediate_1 + dens_ab/18.*(144.*pow(2.,2./3.)*cf*8./3.*pow(id.b.rho,5./3.) + 2.*(11.-delta)*grad_b2/dens - 2./dens*ddelta_drho_b*(id.a.rho*grad_a2 + id.b.rho*grad_b2) - 2.*(11.-delta)/dens2*(id.a.rho*grad_a2 + id.b.rho*grad_b2) - 7.*ddelta_drho_b*(grad_a2+grad_b2+2.*grad_ab) + ddelta_drho_b*(grad_a2+grad_b2) ) - 8./3.*dens*grad_ab - 2.*id.b.rho*grad_a2 ); od.df_drho_b = df1_drho_b + df2_drho_b; od.df_dgamma_bb = -omega*a*b * (dens_ab/9.*(1.-3.*delta + id.b.rho*(11.-delta)/dens) - dens_a2); } } } ///////////////////////////////////////////////////////////////////////////// // Perdew 1986 (P86) Correlation Functional // J. P. Perdew, PRB, 33, 8822, 1986. // C. W. Murray, N. C. Handy and G. J. Laming, Mol. Phys., 78, 997, 1993. // // Coded by Matt Leininger static ClassDesc P86CFunctional_cd( typeid(P86CFunctional),"P86CFunctional",1,"public DenFunctional", 0, create, create); P86CFunctional::P86CFunctional(StateIn& s): SavableState(s), DenFunctional(s) { s.get(a_); s.get(C1_); s.get(C2_); s.get(C3_); s.get(C4_); s.get(C5_); s.get(C6_); s.get(C7_); } P86CFunctional::P86CFunctional() { init_constants(); } P86CFunctional::P86CFunctional(const Ref& keyval): DenFunctional(keyval) { init_constants(); a_ = keyval->doublevalue("a", KeyValValuedouble(a_)); C1_ = keyval->doublevalue("C1", KeyValValuedouble(C1_)); C2_ = keyval->doublevalue("C2", KeyValValuedouble(C2_)); C3_ = keyval->doublevalue("C3", KeyValValuedouble(C3_)); C4_ = keyval->doublevalue("C4", KeyValValuedouble(C4_)); C5_ = keyval->doublevalue("C5", KeyValValuedouble(C5_)); C6_ = keyval->doublevalue("C6", KeyValValuedouble(C6_)); C7_ = keyval->doublevalue("C7", KeyValValuedouble(C7_)); } P86CFunctional::~P86CFunctional() { } void P86CFunctional::save_data_state(StateOut& s) { DenFunctional::save_data_state(s); s.put(a_); s.put(C1_); s.put(C2_); s.put(C3_); s.put(C4_); s.put(C5_); s.put(C6_); s.put(C7_); } void P86CFunctional::init_constants() { a_ = 1.745*0.11; C1_ = 0.001667; C2_ = 0.002568; C3_ = 0.023266; C4_ = 7.389e-6; C5_ = 8.723; C6_ = 0.472; C7_ = 1e4*C4_; } int P86CFunctional::need_density_gradient() { return 1; } void P86CFunctional::point(const PointInputData &id, PointOutputData &od) { od.zero(); // Precalculate terms for efficiency double rho = id.a.rho + id.b.rho; double rho76 = pow(rho, (7./6.)); double rho43 = pow(rho, (4./3.)); double rho13 = pow(rho, (1./3.)); double rho16 = pow(rho, (1./6.)); double rs = pow( (3./(4.*M_PI*rho)), (1./3.)); double rs2 = rs*rs; double rs3 = rs2*rs; double zeta = (id.a.rho - id.b.rho)/rho; double fzeta = pow(2.,(1./3.)) * sqrt( pow(((1.+zeta)/2.),(5./3.)) + pow(((1.-zeta)/2.),(5./3.)) ); double C_infin = C1_ + C2_; double numer = C2_ + C3_*rs + C4_*rs2; double denom = 1.+C5_*rs+C6_*rs2+C7_*rs3; double C_rho = C1_ + numer/denom; double gamma_aa = id.a.gamma; double gamma_bb = id.b.gamma; double gamma_ab = id.gamma_ab; double gamma_total = sqrt(gamma_aa + gamma_bb + 2.*gamma_ab); double gamma_total2 = gamma_total*gamma_total; double Phi = a_ * C_infin * gamma_total / (C_rho * rho76); double fp86 = exp(-Phi) * C_rho * gamma_total2 / (fzeta*rho43); if (rho < MIN_DENSITY) fp86 = 0.; od.energy = fp86; if (compute_potential_) { double drs_drhoa = -rs/(3.*rho); double dCrho_drhoa = drs_drhoa/denom * (C3_+2.*C4_*rs - numer/denom * (C5_+2.*C6_*rs+3.*C7_*rs2)); double dCrho_drhob = dCrho_drhoa; double dzeta_drhoa = 1./rho * (1.-zeta); double dzeta_drhob = 1./rho * (-1.-zeta); double dPhi_drhoa = -Phi/(C_rho*rho76)*(dCrho_drhoa*rho76 + C_rho*(7./6.)*rho16); double dPhi_drhob = dPhi_drhoa; double dfzeta_drhoa = pow(2., (-1./3.))*1./fzeta * (5./3. * pow(((1.+zeta)/2.), (2./3.))*0.5*dzeta_drhoa + 5./3.*pow(((1.-zeta)/2.), (2./3.))*-0.5*dzeta_drhoa); double dfzeta_drhob = pow(2., (-1./3.))*1./fzeta * (5./3. * pow(((1.+zeta)/2.), (2./3.))*0.5*dzeta_drhob + 5./3.*pow(((1.-zeta)/2.), (2./3.))*-0.5*dzeta_drhob); double dfp86_drhoa = fp86/C_rho*(-dPhi_drhoa*C_rho + dCrho_drhoa) - fp86/(fzeta*rho43)*(dfzeta_drhoa*rho43 + fzeta*(4./3.)*rho13); double dfp86_drhob = fp86/C_rho*(-dPhi_drhob*C_rho + dCrho_drhob) - fp86/(fzeta*rho43)*(dfzeta_drhob*rho43 + fzeta*(4./3.)*rho13); if (rho < MIN_DENSITY) dfp86_drhoa = dfp86_drhob = 0.; od.df_drho_a = dfp86_drhoa; od.df_drho_b = dfp86_drhob; // gamma part of potential // double dPhi_dgamma_aa = Phi/(2.*gamma_total2); // double dPhi_dgamma_bb = dPhi_dgamma_aa; // double dfp86_dgamma_aa = fp86*(1./gamma_total2 - dPhi_dgamma_aa); double prefactor = exp(-Phi)*C_rho/( fzeta*rho43 ); double dfp86_dgamma_aa = prefactor * (1.-Phi/2.); double dfp86_dgamma_bb = dfp86_dgamma_aa; if (rho < MIN_DENSITY) dfp86_dgamma_aa = dfp86_dgamma_bb = 0.; od.df_dgamma_aa = dfp86_dgamma_aa; od.df_dgamma_bb = dfp86_dgamma_bb; // double dPhi_dgamma_ab = 2.*dPhi_dgamma_aa; // double dfp86_dgamma_ab = fp86*(2./gamma_total2 - dPhi_dgamma_ab); double dfp86_dgamma_ab = prefactor * (2.-Phi); if (rho < MIN_DENSITY) dfp86_dgamma_ab= 0.; od.df_dgamma_ab = dfp86_dgamma_ab; } } ///////////////////////////////////////////////////////////////////////////// // Perdew 1986 (P86) Correlation Functional // J. P. Perdew, PRB, 33, 8822, 1986. // C. W. Murray, N. C. Handy and G. J. Laming, Mol. Phys., 78, 997, 1993. // // Coded by Matt Leininger static ClassDesc NewP86CFunctional_cd( typeid(NewP86CFunctional),"NewP86CFunctional",1,"public DenFunctional", 0, create, create); NewP86CFunctional::NewP86CFunctional(StateIn& s): SavableState(s), DenFunctional(s) { s.get(a_); s.get(C1_); s.get(C2_); s.get(C3_); s.get(C4_); s.get(C5_); s.get(C6_); s.get(C7_); } NewP86CFunctional::NewP86CFunctional() { init_constants(); } NewP86CFunctional::NewP86CFunctional(const Ref& keyval): DenFunctional(keyval) { init_constants(); a_ = keyval->doublevalue("a", KeyValValuedouble(a_)); C1_ = keyval->doublevalue("C1", KeyValValuedouble(C1_)); C2_ = keyval->doublevalue("C2", KeyValValuedouble(C2_)); C3_ = keyval->doublevalue("C3", KeyValValuedouble(C3_)); C4_ = keyval->doublevalue("C4", KeyValValuedouble(C4_)); C5_ = keyval->doublevalue("C5", KeyValValuedouble(C5_)); C6_ = keyval->doublevalue("C6", KeyValValuedouble(C6_)); C7_ = keyval->doublevalue("C7", KeyValValuedouble(C7_)); } NewP86CFunctional::~NewP86CFunctional() { } void NewP86CFunctional::save_data_state(StateOut& s) { DenFunctional::save_data_state(s); s.put(a_); s.put(C1_); s.put(C2_); s.put(C3_); s.put(C4_); s.put(C5_); s.put(C6_); s.put(C7_); } void NewP86CFunctional::init_constants() { a_ = 1.745*0.11; C1_ = 0.001667; C2_ = 0.002568; C3_ = 0.023266; C4_ = 7.389e-6; C5_ = 8.723; C6_ = 0.472; C7_ = 1e4*C4_; } int NewP86CFunctional::need_density_gradient() { return 1; } double NewP86CFunctional::rho_deriv(double rho_a, double rho_b, double mdr) { double ra0,ra1,ra2,ra3,ra4,ra5,ra6,ra7,ra8,ra9,ra10,ra11,ra12,ra13,ra14, ra15,ra16,ra17,ra18,ra19,ra20; double c_infin, c_1, c_2, c_3, c_4, c_5, c_6, c_7; c_infin = C1_ + C2_; c_1 = C1_; c_2 = C2_; c_3 = C3_; c_4 = C4_; c_5 = C5_; c_6 = C6_; c_7 = C7_; ra0 = pow(mdr,2.0); ra1 = rho_b+rho_a; ra2 = 1/pow(ra1,1.3333333333333333); ra3 = -(1.0*rho_b)+rho_a; ra4 = 1/ra1; // ra4 = 1/pow(ra1,1.0); ra5 = -(1.0*ra3*ra4)+1.0; ra6 = ra3*ra4+1.0; ra7 = 0.3149802624737183*pow(ra6,1.6666666666666667)+ 0.3149802624737183*pow(ra5,1.6666666666666667); ra8 = 1/pow(ra7,0.5); ra9 = 1/(ra1*ra1); ra10 = 1/pow(ra1,1.6666666666666667); ra11 = 1/pow(ra1,0.66666666666666663); ra12 = 1/pow(ra1,0.33333333333333331); ra13 = 0.62035049089940009*c_3*ra12+0.38483473155912662*c_4*ra11+c_2; ra14 = 0.62035049089940009*c_5*ra12+0.38483473155912662*c_6*ra11 +0.238732414637843*c_7*ra4+1.0; ra15 = 1/ra14; ra16 = (-(0.20678349696646667*c_3*ra2)-(0.25655648770608441*c_4*ra10))*ra15- ((1.0*(-(0.20678349696646667*c_5*ra2)-(0.25655648770608441*c_6*ra10)- (0.238732414637843*c_7*ra9))*ra13)/pow(ra14,2.0)); ra17 = 1/pow(ra1,1.1666666666666667); ra18 = ra13*ra15+c_1; ra19 = 1/ra18; ra20 = exp(-1.0*a_*c_infin*mdr*ra17*ra19); double dp86c_drho_a = 0.79370052598409979*ra0*ra2*ra8*ra18* ((1.1666666666666667*a_*c_infin*mdr*ra19)/pow(ra1,2.1666666666666665) +(a_*c_infin*mdr*ra17*ra16)/ra18*ra18)* ra20-((1.0582673679787997*ra0*ra8*ra18*ra20)/ pow(ra1,2.3333333333333335))- ((0.3968502629920499*ra0*ra2*(0.52496710412286385*(ra4-(1.0*ra3*ra9))* pow(ra6,0.66666666666666663)+0.52496710412286385*(-(1.0*ra4)+ra3*ra9) *pow(ra5,0.66666666666666663))*ra18*ra20)/pow(ra7,1.5))+ 0.79370052598409979*ra0*ra2*ra8*ra16*ra20; return dp86c_drho_a; } double NewP86CFunctional::gab_deriv(double rho_a, double rho_b, double mdr) { double c_infin, c_1, c_2, c_3, c_4, c_5, c_6, c_7; c_infin = C1_ + C2_; c_1 = C1_; c_2 = C2_; c_3 = C3_; c_4 = C4_; c_5 = C5_; c_6 = C6_; c_7 = C7_; double g0,g1,g2,g3,g4,g5,g6,g7; g0 = rho_b+rho_a; g1 = -(1.0*rho_b)+rho_a; g2 = 1/g0; g3 = 1/pow(0.3149802624737183*pow(g1*g2+1.0,1.6666666666666667 )+0.3149802624737183*pow(-(1.0*g1*g2)+1.0, 1.6666666666666667),0.5); g4 = 1/pow(g0,0.66666666666666663); g5 = 1/pow(g0,0.33333333333333331); g6 = (0.62035049089940009*c_3*g5+0.38483473155912662*c_4*g4+c_2) /pow(0.62035049089940009*c_5*g5+0.38483473155912662*c_6*g4+ 0.238732414637843*c_7*g2+1.0,1.0)+c_1; g7 = exp(-1.0*a_*c_infin*mdr*1.0/pow(g0,1.1666666666666667)*1.0/g6); double dp86c_dmdr = (1.5874010519681996*mdr*g3*g6*g7)/pow(g0,1.3333333333333333) -((0.79370052598409979*a_*c_infin*pow(mdr,2.0)*g3*g7)/pow(g0,2.5)); return dp86c_dmdr/mdr; } void NewP86CFunctional::point(const PointInputData &id, PointOutputData &od) { od.zero(); // Precalculate terms for efficiency double rho = id.a.rho + id.b.rho; double rs = pow( (3./(4.*M_PI*rho)), (1./3.)); double zet = (id.a.rho - id.b.rho)/rho; double c_infin = C1_ + C2_; double gamma_aa = id.a.gamma; double gamma_bb = id.b.gamma; double gamma_ab = id.gamma_ab; double mdr = sqrt(gamma_aa + gamma_bb + 2.*gamma_ab); double e0 = 1/pow(rho,0.66666666666666663); double e1 = 1/pow(rho,0.33333333333333331); double e2 = (0.62035049089940009*C3_*e1+0.38483473155912662*C4_*e0+C2_) /(0.62035049089940009*C5_*e1+0.38483473155912662*C6_*e0+( 0.238732414637843*C7_)/rho+1.0)+C1_; double fp86 = (0.79370052598409979*pow(mdr,2.0)*e2)*exp(-1.0*a_* c_infin*mdr*1.0/e2*1.0/pow(rho,1.1666666666666667) )/pow(rho,1.3333333333333333)/pow(0.3149802624737183*pow(zet+ 1.0,1.6666666666666667)+0.3149802624737183*pow(-(1.0*zet)+ 1.0,1.6666666666666667),0.5); od.energy += fp86; if (compute_potential_) { double dfp86_drhoa = rho_deriv(id.a.rho, id.b.rho, mdr); double dfp86_drhob = rho_deriv(id.b.rho, id.a.rho, mdr); double dfp86_dgab = gab_deriv(id.a.rho, id.b.rho, mdr); od.df_drho_a += dfp86_drhoa; od.df_drho_b += dfp86_drhob; od.df_dgamma_ab += dfp86_dgab; od.df_dgamma_aa += 0.5*od.df_dgamma_ab; od.df_dgamma_bb += 0.5*od.df_dgamma_ab; } } ///////////////////////////////////////////////////////////////////////////// // PBECFunctional static ClassDesc PBECFunctional_cd( typeid(PBECFunctional),"PBECFunctional",1,"public DenFunctional", 0, create, create); PBECFunctional::PBECFunctional(StateIn& s): SavableState(s), DenFunctional(s) { local_ << SavableState::restore_state(s); s.get(gamma); s.get(beta); } PBECFunctional::PBECFunctional() { local_ = new PW92LCFunctional; local_->set_compute_potential(1); init_constants(); } PBECFunctional::PBECFunctional(const Ref& keyval): DenFunctional(keyval) { local_ << keyval->describedclassvalue("local"); if (local_.null()) local_ = new PW92LCFunctional; local_->set_compute_potential(1); init_constants(); gamma = keyval->doublevalue("gamma", KeyValValuedouble(gamma)); beta = keyval->doublevalue("beta", KeyValValuedouble(beta)); } void PBECFunctional::init_constants() { // in paper // gamma = 0.031091 // beta = 0.066725 // in PBE.f: gamma = 0.03109069086965489503494086371273; beta = 0.06672455060314922; } PBECFunctional::~PBECFunctional() { } void PBECFunctional::save_data_state(StateOut& s) { DenFunctional::save_data_state(s); SavableState::save_state(local_.pointer(),s); s.put(gamma); s.put(beta); } int PBECFunctional::need_density_gradient() { return 1; } void PBECFunctional::set_spin_polarized(int a) { spin_polarized_ = a; local_->set_spin_polarized(a); } double PBECFunctional::rho_deriv(double rho_a, double rho_b, double mdr, double ec_local, double ec_local_dra) { if (mdr < MIN_SQRTGAMMA) { return 0; } if (rho_b < MIN_DENSITY) { #define Log(x) log(x) #define Power(x,y) pow(x,y) #define Pi M_PI #define E M_E double ec = ec_local; double decdrhoa = ec_local_dra; double rhoa = rho_a; double result = (gamma*((-2*beta*Power(mdr,2)*Power(Pi,0.3333333333333333)*rhoa* (Power(beta,2)*decdrhoa*Power(E,(4*ec)/gamma)*Power(mdr,4)* Power(Pi,0.6666666666666666)* (Power(6,0.6666666666666666)*beta*Power(E,(2*ec)/gamma)* Power(mdr,2)*Power(Pi,0.3333333333333333) - 96*(-1 + Power(E,(2*ec)/gamma))*gamma* Power(rhoa,2.3333333333333335)) + 896*Power(6,0.3333333333333333)* Power(-1 + Power(E,(2*ec)/gamma),3)*Power(gamma,3)* Power(rhoa,3.6666666666666665)* (-(beta*Power(E,(2*ec)/gamma)*Power(mdr,2)* Power(Pi,0.3333333333333333)) + 4*Power(6,0.3333333333333333)*(-1 + Power(E,(2*ec)/gamma))* gamma*Power(rhoa,2.3333333333333335))))/ (gamma*(Power(6,0.3333333333333333)*Power(beta,2)* Power(E,(2*ec)/gamma)*Power(mdr,4)*Power(Pi,0.6666666666666666)\ - 8*Power(6,0.6666666666666666)*beta* (-1 + Power(E,(2*ec)/gamma))*gamma*Power(mdr,2)* Power(Pi,0.3333333333333333)*Power(rhoa,2.3333333333333335) + 384*Power(-1 + Power(E,(2*ec)/gamma),2)*Power(gamma,2)* Power(rhoa,4.666666666666667))* (Power(6,0.3333333333333333)*Power(beta,2)*Power(E,(4*ec)/gamma)* Power(mdr,4)*Power(Pi,0.6666666666666666) - 8*Power(6,0.6666666666666666)*beta*Power(E,(2*ec)/gamma)* (-1 + Power(E,(2*ec)/gamma))*gamma*Power(mdr,2)* Power(Pi,0.3333333333333333)*Power(rhoa,2.3333333333333335) + 384*Power(-1 + Power(E,(2*ec)/gamma),2)*Power(gamma,2)* Power(rhoa,4.666666666666667))) + Log(1 + (beta*(-1 + Power(E,(2*ec)/gamma))*Power(mdr,2)* Power(Pi/6.,0.3333333333333333)* (Power(6,0.6666666666666666)*beta*Power(E,(2*ec)/gamma)* Power(mdr,2)*Power(Pi,0.3333333333333333) - 48*(-1 + Power(E,(2*ec)/gamma))*gamma* Power(rhoa,2.3333333333333335)))/ (-(Power(6,0.3333333333333333)*Power(beta,2)*Power(E,(4*ec)/gamma)* Power(mdr,4)*Power(Pi,0.6666666666666666)) + 8*Power(6,0.6666666666666666)*beta*Power(E,(2*ec)/gamma)* (-1 + Power(E,(2*ec)/gamma))*gamma*Power(mdr,2)* Power(Pi,0.3333333333333333)*Power(rhoa,2.3333333333333335) - 384*Power(-1 + Power(E,(2*ec)/gamma),2)*Power(gamma,2)* Power(rhoa,4.666666666666667)))))/2.; return result; } if (rho_a < MIN_DENSITY) { // df_drho_a diverges for this case return 0.0; } double ra0,ra1,ra2,ra3,ra4,ra5,ra6,ra7,ra8,ra9,ra10,ra11,ra12,ra13,ra14, ra15,ra16,ra17,ra18,ra19,ra20,ra21,ra22,ra23,ra24,ra25,ra26,ra27,ra28, ra29,ra30,ra31,ra32,ra33,ra34,ra35; double dpbec_drho_a; ra0 = rho_b+rho_a; ra1 = -(1.0*rho_b)+rho_a; ra2 = 1/pow(ra0,2.0); ra3 = 1/pow(ra0,1.0); ra4 = -(1.0*ra1*ra3)+1.0; ra5 = ra1*ra3+1.0; ra6 = (0.66666666666666663*(ra3-(1.0*ra1*ra2)))/pow(ra5, 0.33333333333333331)+(0.66666666666666663*(-(1.0*ra3)+ra1*ra2 ))/pow(ra4,0.33333333333333331); ra7 = pow(ra5,0.66666666666666663)+pow(ra4,0.66666666666666663); ra8 = pow(ra7,2.0); ra9 = pow(mdr,2.0); ra10 = 1/pow(ra0,2.3333333333333335); ra11 = 1/ra8; ra12 = pow(ra7,3.0); ra13 = 1/ra12; ra14 = ec_local; ra15 = 1/pow(gamma,1.0); ra16 = 1/exp(8.0*ra13*ra14*ra15); ra17 = ra16-1.0; ra18 = 1/pow(ra17,1.0); ra19 = 0.25387282439081477*beta*ra9*ra10*ra11*ra18*ra15; ra20 = ra19+1.0; ra21 = pow(beta,2.0); ra22 = pow(mdr,4.0); ra23 = 1/pow(ra0,4.666666666666667); ra24 = 1/pow(ra7,4.0); ra25 = 1/pow(ra17,2.0); ra26 = 1/pow(gamma,2.0); ra27 = ra19+0.064451410964169495*ra21*ra22*ra23*ra24*ra25*ra26+ 1.0; ra28 = 1/pow(ra27,1.0); ra29 = 0.25387282439081477*beta*ra9*ra10*ra11*ra20*ra28*ra15+1.0 ; ra30 = log(ra29); ra31 = 1/pow(ra0,3.3333333333333335); ra32 = -(0.50774564878162953*beta*ra9*ra10*ra6*ra13*ra18*ra15); ra33 = -(0.59236992357856788*beta*ra9*ra31*ra11*ra18*ra15); ra34 = -(8.0*ra13*ec_local_dra*ra15)+24.0*ra6* ra24*ra14*ra15; ra35 = -(0.25387282439081477*beta*ra9*ra10*ra11*ra25*ra16*ra34* ra15); dpbec_drho_a = (0.125*ra0*ra12*(-((0.25387282439081477*beta*ra9* ra10*ra11*ra20*(ra35+ra33+ra32-((0.12890282192833899*ra21*ra22* ra23*ra24*ra16*ra34*ra26)/pow(ra17,3.0))-((0.30077325116612436* ra21*ra22*ra24*ra25*ra26)/pow(ra0,5.666666666666667))-(( 0.25780564385667798*ra21*ra22*ra23*ra6*ra25*ra26)/pow(ra7,5.0)) )*ra15)/pow(ra27,2.0))+0.25387282439081477*beta*ra9*ra10*ra11* ra28*(ra35+ra33+ra32)*ra15-(0.59236992357856788*beta*ra9*ra31* ra11*ra20*ra28*ra15)-(0.50774564878162953*beta*ra9*ra10*ra6*ra13* ra20*ra28*ra15))*gamma)/pow(ra29,1.0)+0.125*ra12*ra30*gamma+ 0.375*ra0*ra6*ra8*ra30*gamma; return dpbec_drho_a; } double PBECFunctional::gab_deriv(double rho, double phi, double mdr, double ec_local) { if (rho < MIN_DENSITY) return 0; if (mdr < MIN_SQRTGAMMA) { double result = (beta*phi*pow(M_PI/3.,1./3.))/(8.*pow(rho,4./3.)); return result; } double g0,g1,g2,g3,g4,g5,g6,g7,g8,g9,g10,g11,g12,g13,g14,g15,g16; double dpbec_dmdr; g0 = pow(phi,3.0); g1 = pow(beta,2.0); g2 = pow(mdr,3.0); g3 = 1/pow(phi,4.0); g4 = 1/pow(rho,4.666666666666667); g5 = 1/pow(gamma,1.0); g6 = 1/exp(1.0*1.0/g0*ec_local*g5)-1.0; g7 = 1/pow(g6,1.0); g8 = 1/pow(g6,2.0); g9 = 1/pow(gamma,2.0); g10 = pow(mdr,2.0); g11 = 1/pow(phi,2.0); g12 = 1/pow(rho,2.3333333333333335); g13 = 0.063468206097703692*beta*g10*g11*g12*g7*g5; g14 = g13+0.0040282131852605934*g1*pow(mdr,4.0)*g3*g4*g8*g9+ 1.0; g15 = 1/pow(g14,1.0); g16 = g13+1.0; dpbec_dmdr = (g0*rho*(0.12693641219540738*beta*mdr*g11*g12*g16*g15 *g5-((0.063468206097703692*beta*g10*g11*g12*( 0.12693641219540738*beta*mdr*g11*g12*g7*g5+0.016112852741042374 *g1*g2*g3*g4*g8*g9)*g16*g5)/pow(g14,2.0))+0.0080564263705211869 *g1*g2*g3*g4*g7*g15*g9)*gamma)/pow(0.063468206097703692*beta*g10* g11*g12*g16*g15*g5+1.0,1.0); return dpbec_dmdr/mdr; } void PBECFunctional::point(const PointInputData &id, PointOutputData &od) { double ec_local, dec_local_rs, dec_local_zeta; local_->point_lc(id, od, ec_local, dec_local_rs, dec_local_zeta); double rho = id.a.rho+id.b.rho; double rho_13 = pow(rho, 1./3.); double rho_43 = rho*rho_13; double zeta = (id.a.rho - id.b.rho)/rho; double phi = 0.5*(pow(1+zeta, 2./3.)+pow(1-zeta, 2./3.)); double mdr = sqrt(id.a.gamma + id.b.gamma + 2*id.gamma_ab); double pbec; double e0,e1,e2,e3,e4,e5,e6; e0 = pow(phi,3.0); e1 = pow(mdr,2.0); e2 = 1/pow(phi,2.0); e3 = 1/pow(rho,2.3333333333333335); e4 = 1/pow(gamma,1.0); e5 = 1/exp(1.0*1.0/e0*ec_local*e4)-1.0; e6 = (0.063468206097703692*beta*e1*e2*e3*e4)/pow(e5,1.0); pbec = e0*rho*log((0.063468206097703692*beta*e1*e2*e3*(e6+1.0)* e4)/pow(e6+(0.0040282131852605934*pow(beta,2.0)*pow(mdr,4.0)) /pow(phi,4.0)/pow(rho,4.666666666666667)/pow(e5,2.0)/pow( gamma,2.0)+1.0,1.0)+1.0)*gamma; if (compute_potential_) { double drs_drho_a = -0.20678349696646667/rho_43; // == drs_drho_b double dzeta_drho_a = 0.; if (zeta < MAX_ZETA) dzeta_drho_a = 1./rho * ( 1. - zeta); double dzeta_drho_b = 0.; if (zeta > MIN_ZETA) dzeta_drho_b = 1./rho * (-1. - zeta); //double ec_local_dra = od.df_drho_a; //double ec_local_drb = od.df_drho_b; double ec_local_dra = dec_local_rs*drs_drho_a + dec_local_zeta*dzeta_drho_a; double ec_local_drb = dec_local_rs*drs_drho_a + dec_local_zeta*dzeta_drho_b; double df_drho_a = rho_deriv(id.a.rho, id.b.rho, mdr, ec_local, ec_local_dra); double df_drho_b = rho_deriv(id.b.rho, id.a.rho, mdr, ec_local, ec_local_drb); double df_dgab = gab_deriv(rho, phi, mdr, ec_local); od.df_drho_a += df_drho_a; od.df_drho_b += df_drho_b; od.df_dgamma_aa += 0.5*df_dgab; od.df_dgamma_bb += 0.5*df_dgab; od.df_dgamma_ab += df_dgab; } od.energy += pbec; // cout << scprintf("id.a.del_rho = %12.8f %12.8f %12.8f", id.a.del_rho[0], // id.a.del_rho[1], id.a.del_rho[2]) // << endl; // cout << scprintf("id.b.del_rho = %12.8f %12.8f %12.8f", id.b.del_rho[0], // id.b.del_rho[1], id.b.del_rho[2]) // << endl; // cout << "id.a.gamma = " << id.a.gamma << endl; // cout << "id.b.gamma = " << id.b.gamma << endl; // cout << "od.df_drho_a = " << od.df_drho_a << endl; // cout << "od.df_drho_b = " << od.df_drho_b << endl; // cout << "od.df_dgamma_aa = " << od.df_dgamma_aa << endl; // cout << "od.df_dgamma_ab = " << od.df_dgamma_ab << endl; // cout << "od.df_dgamma_bb = " << od.df_dgamma_bb << endl; } ///////////////////////////////////////////////////////////////////////////// // PW91CFunctional static ClassDesc PW91CFunctional_cd( typeid(PW91CFunctional),"PW91CFunctional",1,"public DenFunctional", 0, create, create); PW91CFunctional::PW91CFunctional(StateIn& s): SavableState(s), DenFunctional(s) { local_ << SavableState::restore_state(s); init_constants(); } PW91CFunctional::PW91CFunctional() { local_ = new PW92LCFunctional; local_->set_compute_potential(1); init_constants(); } PW91CFunctional::PW91CFunctional(const Ref& keyval): DenFunctional(keyval) { local_ << keyval->describedclassvalue("local"); if (local_.null()) local_ = new PW92LCFunctional; local_->set_compute_potential(1); init_constants(); } void PW91CFunctional::init_constants() { a = 23.266; b = 7.389e-3; c = 8.723; d = 0.472; alpha = 0.09; c_c0 = 0.004235; // c_x = -0.001667 in Phys Rev B 46, p 6671, Perdew, et. al. // c_x as in PBE.f: c_x = -0.001667212; } PW91CFunctional::~PW91CFunctional() { } void PW91CFunctional::save_data_state(StateOut& s) { DenFunctional::save_data_state(s); SavableState::save_state(local_.pointer(),s); } int PW91CFunctional::need_density_gradient() { return 1; } void PW91CFunctional::set_spin_polarized(int a) { spin_polarized_ = a; local_->set_spin_polarized(a); } double PW91CFunctional::limit_df_drhoa(double rhoa, double mdr, double ec, double decdrhoa) { double result; // blame mathematica double v = 15.755920349483144; double cx = c_x; double cc0 = c_c0; double beta = v * cc0; double e2ec = Power(E,(2*alpha*ec)/Power(beta,2)); double e4ec = e2ec * e2ec; double e8ec = e4ec * e4ec; double e25mdr2 = Power(E,-(25*Power(mdr,2))/ (Power(6,0.6666666666666666)*Power(Pi,1.3333333333333333)* Power(rhoa,2.6666666666666665))); result = (Power(mdr,2)*Power(Pi/6.,0.3333333333333333)* (1750*Power(6,0.3333333333333333)*a*Power(Pi,0.6666666666666666) - 1750000*Power(6,0.3333333333333333)*c*cc0* Power(Pi,0.6666666666666666) - 2500000*Power(6,0.3333333333333333)*c*cx* Power(Pi,0.6666666666666666) + (8988*Pi)/Power(1/rhoa,0.3333333333333333) - (3500000*cc0*Pi)/Power(1/rhoa,0.3333333333333333) - (5000000*cx*Pi)/Power(1/rhoa,0.3333333333333333) + 875*Power(6,0.6666666666666666)*b*Power(Pi,0.3333333333333333)* Power(1/rhoa,0.3333333333333333) - 875000*Power(6,0.6666666666666666)*cc0*d* Power(Pi,0.3333333333333333)*Power(1/rhoa,0.3333333333333333) - 1250000*Power(6,0.6666666666666666)*cx*d* Power(Pi,0.3333333333333333)*Power(1/rhoa,0.3333333333333333) - 26250000*b*cc0*Power(1/rhoa,0.6666666666666666) - 37500000*b*cx*Power(1/rhoa,0.6666666666666666))*v) *e25mdr2/(1.4e7* (2*Power(6,0.3333333333333333)*c*Power(Pi,0.6666666666666666) + (4*Pi)/Power(1/rhoa,0.3333333333333333) + Power(6,0.6666666666666666)*d*Power(Pi,0.3333333333333333)* Power(1/rhoa,0.3333333333333333) + 30*b*Power(1/rhoa,0.6666666666666666))*Power(rhoa,2.3333333333333335) ); result += rhoa*((Power(beta,2)* ((-2*alpha*(-(alpha*e4ec*Power(mdr,4)* Power(Pi/6.,0.6666666666666666))/ (32.*beta*(-1 + e4ec)*Power(rhoa,4.666666666666667)) + (Power(mdr,2)*Power(Pi/6.,0.3333333333333333))/ (8.*Power(rhoa,2.3333333333333335)))* ((-7*Power(alpha,2)*e8ec*Power(mdr,4)* Power(Pi/6.,0.6666666666666666))/ (24.*beta*Power(-1 + e4ec,2)*Power(rhoa,5.666666666666667))\ - (Power(alpha,3)*decdrhoa*e8ec*Power(mdr,4)* Power(Pi/6.,0.6666666666666666))/ (2.*Power(beta,3)*Power(-1 + e4ec,3)* Power(rhoa,4.666666666666667)) + (7*alpha*e4ec*Power(mdr,2)*Power(Pi/6.,0.3333333333333333))/ (12.*(-1 + e4ec)*Power(rhoa,3.3333333333333335)) + (Power(alpha,2)*decdrhoa*e4ec*Power(mdr,2)* Power(Pi/6.,0.3333333333333333))/ (Power(beta,2)*Power(-1 + e4ec,2)* Power(rhoa,2.3333333333333335))))/ Power(beta + (Power(alpha,2)*e8ec*Power(mdr,4)* Power(Pi/6.,0.6666666666666666))/ (16.*beta*Power(-1 + e4ec,2)*Power(rhoa,4.666666666666667)) - (alpha*e4ec*Power(mdr,2)*Power(Pi/6.,0.3333333333333333))/ (4.*(-1 + e4ec)*Power(rhoa,2.3333333333333335)),2) + (2*alpha*((7*alpha*e4ec*Power(mdr,4)* Power(Pi/6.,0.6666666666666666))/ (48.*beta*(-1 + e4ec)*Power(rhoa,5.666666666666667)) + (Power(alpha,2)*decdrhoa*e4ec*Power(mdr,4)* Power(Pi/6.,0.6666666666666666))/ (8.*Power(beta,3)*Power(-1 + e4ec,2)* Power(rhoa,4.666666666666667)) - (7*Power(mdr,2)*Power(Pi/6.,0.3333333333333333))/ (24.*Power(rhoa,3.3333333333333335))))/ (beta + (Power(alpha,2)*e8ec*Power(mdr,4)* Power(Pi/6.,0.6666666666666666))/ (16.*beta*Power(-1 + e4ec,2)*Power(rhoa,4.666666666666667)) - (alpha*e4ec*Power(mdr,2)*Power(Pi/6.,0.3333333333333333))/ (4.*(-1 + e4ec)*Power(rhoa,2.3333333333333335)))))/ (4.*alpha*(1 + (2*alpha* (-(alpha*e4ec*Power(mdr,4)*Power(Pi/6.,0.6666666666666666))/ (32.*beta*(-1 + e4ec)*Power(rhoa,4.666666666666667)) + (Power(mdr,2)*Power(Pi/6.,0.3333333333333333))/ (8.*Power(rhoa,2.3333333333333335))))/ (beta + (Power(alpha,2)*e8ec*Power(mdr,4)* Power(Pi/6.,0.6666666666666666))/ (16.*beta*Power(-1 + e4ec,2)*Power(rhoa,4.666666666666667)) - (alpha*e4ec*Power(mdr,2)*Power(Pi/6.,0.3333333333333333))/ (4.*(-1 + e4ec)*Power(rhoa,2.3333333333333335))))) + (Power(mdr,4)*(1750*Power(6,0.3333333333333333)*a* Power(Pi,0.6666666666666666) - 1750000*Power(6,0.3333333333333333)*c*cc0* Power(Pi,0.6666666666666666) - 2500000*Power(6,0.3333333333333333)*c*cx* Power(Pi,0.6666666666666666) + (8988*Pi)/Power(1/rhoa,0.3333333333333333) - (3500000*cc0*Pi)/Power(1/rhoa,0.3333333333333333) - (5000000*cx*Pi)/Power(1/rhoa,0.3333333333333333) + 875*Power(6,0.6666666666666666)*b*Power(Pi,0.3333333333333333)* Power(1/rhoa,0.3333333333333333) - 875000*Power(6,0.6666666666666666)*cc0*d* Power(Pi,0.3333333333333333)*Power(1/rhoa,0.3333333333333333) - 1250000*Power(6,0.6666666666666666)*cx*d* Power(Pi,0.3333333333333333)*Power(1/rhoa,0.3333333333333333) - 26250000*b*cc0*Power(1/rhoa,0.6666666666666666) - 37500000*b*cx*Power(1/rhoa,0.6666666666666666))*v) *e25mdr2/(1.26e6*Pi* (2*Power(6,0.3333333333333333)*c*Power(Pi,0.6666666666666666) + (4*Pi)/Power(1/rhoa,0.3333333333333333) + Power(6,0.6666666666666666)*d*Power(Pi,0.3333333333333333)* Power(1/rhoa,0.3333333333333333) + 30*b*Power(1/rhoa,0.6666666666666666))*Power(rhoa,6)) - (Power(mdr,2)*Power(Pi/6.,0.3333333333333333)* (1750*Power(6,0.3333333333333333)*a*Power(Pi,0.6666666666666666) - 1750000*Power(6,0.3333333333333333)*c*cc0* Power(Pi,0.6666666666666666) - 2500000*Power(6,0.3333333333333333)*c*cx* Power(Pi,0.6666666666666666) + (8988*Pi)/Power(1/rhoa,0.3333333333333333) - (3500000*cc0*Pi)/Power(1/rhoa,0.3333333333333333) - (5000000*cx*Pi)/Power(1/rhoa,0.3333333333333333) + 875*Power(6,0.6666666666666666)*b*Power(Pi,0.3333333333333333)* Power(1/rhoa,0.3333333333333333) - 875000*Power(6,0.6666666666666666)*cc0*d* Power(Pi,0.3333333333333333)*Power(1/rhoa,0.3333333333333333) - 1250000*Power(6,0.6666666666666666)*cx*d* Power(Pi,0.3333333333333333)*Power(1/rhoa,0.3333333333333333) - 26250000*b*cc0*Power(1/rhoa,0.6666666666666666) - 37500000*b*cx*Power(1/rhoa,0.6666666666666666))*v)*e25mdr2/ (6.e6* (2*Power(6,0.3333333333333333)*c*Power(Pi,0.6666666666666666) + (4*Pi)/Power(1/rhoa,0.3333333333333333) + Power(6,0.6666666666666666)*d*Power(Pi,0.3333333333333333)* Power(1/rhoa,0.3333333333333333) + 30*b*Power(1/rhoa,0.6666666666666666))* Power(rhoa,3.3333333333333335)) + (Power(mdr,2)*Power(Pi/6.,0.3333333333333333)* (1875*Power(6,0.6666666666666666)*Power(b,2)* Power(Pi,0.3333333333333333) - (500*Power(6,0.3333333333333333)*a*Power(Pi,1.6666666666666667))/ Power(1/rhoa,1.3333333333333333) + (1284*Power(6,0.3333333333333333)*c*Power(Pi,1.6666666666666667))/ Power(1/rhoa,1.3333333333333333) + (57780*b*Pi)/Power(1/rhoa,0.6666666666666666) - (750*b*c*Pi)/Power(1/rhoa,0.6666666666666666) + (750*a*d*Pi)/Power(1/rhoa,0.6666666666666666) + (7500*Power(6,0.3333333333333333)*a*b* Power(Pi,0.6666666666666666))/Power(1/rhoa,0.3333333333333333)\ - 500*Power(6,0.6666666666666666)*b*Power(Pi,1.3333333333333333)* rhoa + 1284*Power(6,0.6666666666666666)*d* Power(Pi,1.3333333333333333)*rhoa)*v)*e25mdr2/ (3.e6* Power(2*Power(6,0.3333333333333333)*c* Power(Pi,0.6666666666666666) + (4*Pi)/Power(1/rhoa,0.3333333333333333) + Power(6,0.6666666666666666)*d*Power(Pi,0.3333333333333333)* Power(1/rhoa,0.3333333333333333) + 30*b*Power(1/rhoa,0.6666666666666666),2)* Power(rhoa,4.333333333333333))) + (Power(beta,2)*Log(1 + (2*alpha* (-(alpha*e4ec*Power(mdr,4)*Power(Pi/6.,0.6666666666666666))/ (32.*beta*(-1 + e4ec)*Power(rhoa,4.666666666666667)) + (Power(mdr,2)*Power(Pi/6.,0.3333333333333333))/ (8.*Power(rhoa,2.3333333333333335))))/ (beta + (Power(alpha,2)*e8ec*Power(mdr,4)* Power(Pi/6.,0.6666666666666666))/ (16.*beta*Power(-1 + e4ec,2)*Power(rhoa,4.666666666666667)) - (alpha*e4ec*Power(mdr,2)*Power(Pi/6.,0.3333333333333333))/ (4.*(-1 + e4ec)*Power(rhoa,2.3333333333333335)))))/(4.*alpha) ; return result; } void PW91CFunctional::point(const PointInputData &id, PointOutputData &od) { double ec_local, dec_local_rs, dec_local_zeta; local_->point_lc(id, od, ec_local, dec_local_rs, dec_local_zeta); double rho = id.a.rho+id.b.rho; double rho_13 = pow(rho, 1./3.); double rho_43 = rho*rho_13; double rs = 0.62035049089940009/rho_13; double z = (id.a.rho - id.b.rho)/rho; double gamma = sqrt(id.a.gamma + id.b.gamma + 2*id.gamma_ab); double pwc, dpwc_drs, dpwc_dg; if (rho < MIN_DENSITY) return; if (gamma < MIN_SQRTGAMMA) { if (!compute_potential_) return; double limit_dpwc_dgaa, limit_dpwc_dgab; double ga0; ga0 = 6.2337093539550051e7*b*c_x*pow(rs,7.0)+(6233709.3539550053 *c_x*d-(4363.596547768504*b))*pow(rs,6.0)+(6233709.3539550053 *c*c_x-(4363.596547768504*a))*pow(rs,5.0)+(6233709.3539550053 *c_x-11205.715934669519)*pow(rs,4.0); limit_dpwc_dgaa = -((1.0*(1.4645918875615231*ga0*pow(z+1.0, 0.66666666666666663)+1.4645918875615231*ga0*pow(-(1.0*z)+ 1.0,0.66666666666666663)))/pow(1.8929525610284735e7*b*pow(rs, 3.0)+1892952.5610284733*d*pow(rs,2.0)+1892952.5610284733*c* rs+1892952.5610284733,1.0)); double gab0; gab0 = 6.2337093539550051e7*b*c_x*pow(rs,7.0)+( 6233709.3539550053*c_x*d-(4363.596547768504*b))*pow(rs,6.0)+( 6233709.3539550053*c*c_x-(4363.596547768504*a))*pow(rs,5.0)+( 6233709.3539550053*c_x-11205.715934669519)*pow(rs,4.0); limit_dpwc_dgab = -((1.0*(1.4645918875615231*gab0*pow(z+1.0, 0.66666666666666663)+1.4645918875615231*gab0*pow(-(1.0*z)+ 1.0,0.66666666666666663)))/pow(9464762.8051423673*b*pow(rs, 3.0)+946476.28051423666*d*pow(rs,2.0)+946476.28051423666*c* rs+946476.28051423666,1.0)); od.df_dgamma_aa += limit_dpwc_dgaa; od.df_dgamma_bb += limit_dpwc_dgaa; od.df_dgamma_ab += limit_dpwc_dgab; return; } double e0,e1,e2,e3,e4,e5,e6,e7,e8,e9,e10,e11,e12,e13,e14,e15; e2 = rs*rs; // pow(rs,2.0); e0 = e2*rs; // pow(rs,3.0); e1 = e0*e0*rs; // pow(rs,7.0); e3 = pow(z+1.0,2./3.)+pow(-z+1.0, 2./3.); e4 = gamma*gamma; // pow(gamma,2.0); e5 = e3*e3; // pow(e3,2.0); e6 = c_c0*c_c0; // pow(c_c0,2.0); e7 = e3*e3*e3; // pow(e3,3.0); e8 = 1./c_c0; // 1/pow(c_c0,1.0); e9 = 1/e5; e10 = 1/e6; e11 = exp(-0.064451410964169495*alpha*e10*ec_local/e7)-1.0; e12 = 1./e11; // 1/pow(e11,1.0); e13 = e1*e1; // pow(rs,14.0); e14 = 1/(e7*e3); // pow(e3,4.0); e15 = e4*e4; // pow(gamma,4.0); pwc = (0.238732414637843*((15.515564128703568*e6*e7*log(( 0.12693641219540738*alpha*e8*(6.5448368524534253*alpha*e8*e13* e14*e12*e15+7.18052672676657*e1*e9*e4))/(( 0.83077810845472067*alpha*alpha*e10*e13*e14*e15)/(e11*e11) +0.91147030036898102*alpha*e8*e1*e9*e12*e4+1.0)+ 1.0))/alpha+(14.141975896783627*e1*((0.001*(b*e2+a *rs+2.568))/(10.0*b*e0+d*e2+c*rs+1.0)-( 1.4285714285714286*c_x)-(1.0*c_c0))*e3*e4)*exp(- 29.773894288156065*e1*rs*e5*e4)))/e0; if (compute_potential_) { double drs_drhoa = -0.20678349696646667/rho_43; double drs_drhob = drs_drhoa; double r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,r13,r14,r15,r16,r17,r18 ,r19,r20,r21,r22,r23,r24,r25,r26,r27,r28,r29,r30,r31,r32,r33,t0; r0 = pow(rs,3.0); r1 = 1/pow(alpha,1.0); r2 = pow(c_c0,2.0); r3 = pow(z+1.0,0.66666666666666663)+pow(-(1.0*z)+1.0, 0.66666666666666663); r4 = pow(r3,3.0); r5 = 1/pow(c_c0,1.0); r6 = pow(rs,7.0); r7 = pow(r3,2.0); r8 = 1/r7; r9 = 1/r2; r10 = exp(-0.064451410964169495*alpha*r9*ec_local*1.0/r4); r11 = r10-1.0; r12 = 1/pow(r11,1.0); r13 = pow(gamma,2.0); r14 = pow(alpha,2.0); r15 = pow(rs,14.0); r16 = 1/pow(r3,4.0); r17 = 1/pow(r11,2.0); r18 = pow(gamma,4.0); r19 = 0.83077810845472067*r14*r9*r15*r16*r17*r18+ 0.91147030036898102*alpha*r5*r6*r8*r12*r13+1.0; r20 = 1/pow(r19,1.0); r21 = 6.5448368524534253*alpha*r5*r15*r16*r12*r18+ 7.18052672676657*r6*r8*r13; r22 = 0.12693641219540738*alpha*r5*r20*r21+1.0; r23 = pow(rs,6.0); r24 = 1/pow(c_c0,3.0); r25 = dec_local_rs; r26 = pow(rs,13.0); r27 = 1/pow(r3,7.0); r28 = pow(rs,2.0); r29 = b*r28+a*rs+2.568; r30 = 10.0*b*r0+d*r28+c*rs+1.0; r31 = 1/pow(r30,1.0); r32 = exp(-29.773894288156065*pow(rs,8.0)*r7*r13); r33 = 0.001*r29*r31-(1.4285714285714286*c_x)-(1.0*c_c0); t0 = -((0.71619724391352901*(15.515564128703568*r1*r2*r4*log (r22)+14.141975896783627*r6*r33*r3*r13*r32))/pow(rs,4.0)); dpwc_drs = t0+(0.238732414637843*(-(3368.493563011893*r15* r33*r4*r18*r32)+98.993831277485398*r23*r33*r3*r13*r32+ 14.141975896783627*r6*(0.001*(2.0*b*rs+a)*r31-((0.001* r29*(30.0*b*r28+2.0*d*rs+c))/pow(r30,2.0)))*r3*r13*r32+( 15.515564128703568*r1*r2*r4*(0.12693641219540738*alpha*r5* r20*(0.42182396967091729*r14*r24*r25*r15*r27*r17*r10*r18+ 91.627715934347961*alpha*r5*r26*r16*r12*r18+ 50.263687087365994*r23*r8*r13)-((0.12693641219540738*alpha* r5*r21*((0.10708964257610123*pow(alpha,3.0)*r25*r15*r27*r10 *r18)/pow(c_c0,4.0)/pow(r11,3.0)+11.630893518366092*r14* r9*r26*r16*r17*r18+(0.058745546910716179*r14*r24*r25*r6*r17* r10*r13)/pow(r3,5.0)+6.3802921025828665*alpha*r5*r23*r8*r12 *r13))/pow(r19,2.0))))/pow(r22,1.0)))/r0; if (id.a.rho > MIN_DENSITY && id.b.rho > MIN_DENSITY) { double dpwc_dz; double z0,z1,z2,z3,z4,z5,z6,z7,z8,z9,z10,z11,z12,z13,z14,z15,z16,z17 ,z18 ,z19,z20,z21,z22,z23,z24,z25,z26,z27,z28,z29,z30,z31; z0 = pow(rs,3.0); z1 = 1/pow(alpha,1.0); z2 = pow(c_c0,2.0); z3 = -(1.0*z)+1.0; z4 = z+1.0; z5 = pow(z4,0.66666666666666663)+pow(z3,0.66666666666666663); z6 = pow(z5,3.0); z7 = 1/pow(c_c0,1.0); z8 = pow(rs,7.0); z9 = pow(z5,2.0); z10 = 1/z9; z11 = 1/z2; z12 = 1/z6; z13 = exp(-0.064451410964169495*alpha*z11*ec_local*z12); z14 = z13-1.0; z15 = 1/pow(z14,1.0); z16 = pow(gamma,2.0); z17 = pow(alpha,2.0); z18 = pow(rs,14.0); z19 = 1/pow(z5,4.0); z20 = 1/pow(z14,2.0); z21 = pow(gamma,4.0); z22 = 0.83077810845472067*z17*z11*z18*z19*z20*z21+ 0.91147030036898102*alpha*z7*z8*z10*z15*z16+1.0; z23 = 1/pow(z22,1.0); z24 = 6.5448368524534253*alpha*z7*z18*z19*z15*z21+ 7.18052672676657*z8*z10*z16; z25 = 0.12693641219540738*alpha*z7*z23*z24+1.0; z26 = 0.66666666666666663/pow(z4,0.33333333333333331)-( 0.66666666666666663/pow(z3,0.33333333333333331)); z27 = -(0.064451410964169495*alpha*z11*dec_local_zeta*z12) +0.19335423289250847*alpha*z11*ec_local*z26*z19; z28 = 1/pow(z5,5.0); z29 = pow(rs,2.0); z30 = (0.001*(b*z29+a*rs+2.5680000000000001))/pow(10.0*b*z0+d* z29+c*rs+1.0,1.0)-(1.4285714285714286*c_x)-(1.0*c_c0); z31 = exp(-29.773894288156065*pow(rs,8.0)*z9*z16); dpwc_dz = (0.238732414637843*(46.546692386110699*z1*z2*z26*z9* log(z25)-(842.12339075297325*pow(rs,15.0)*z30*z26*z9*z21*z31)+ 14.141975896783627*z8*z30*z26*z16*z31+(15.515564128703568*z1*z2 *z6*(0.12693641219540738*alpha*z7*z23*(-(6.5448368524534253* alpha*z7*z18*z19*z27*z20*z13*z21)-(26.179347409813701*alpha*z7* z18*z26*z28*z15*z21)-(14.36105345353314*z8*z26*z12*z16))-(( 0.12693641219540738*alpha*z7*z24*(-((1.6615562169094413*z17*z11 *z18*z19*z27*z13*z21)/pow(z14,3.0))-(3.3231124338188827*z17*z11 *z18*z26*z28*z20*z21)-(0.91147030036898102*alpha*z7*z8*z10*z27* z20*z13*z16)-(1.822940600737962*alpha*z7*z8*z26*z12*z15*z16)))/ pow(z22,2.0))))/pow(z25,1.0)))/z0; double dz_drhoa = ( 1. - (id.a.rho-id.b.rho)/rho)/rho; double dz_drhob = (-1. - (id.a.rho-id.b.rho)/rho)/rho; od.df_drho_a += dpwc_drs * drs_drhoa + dpwc_dz * dz_drhoa; od.df_drho_b += dpwc_drs * drs_drhob + dpwc_dz * dz_drhob; } else if (id.a.rho > MIN_DENSITY) { // df_drho_b diverges double dzeta_drhoa = 1./rho * (1. - z); double drs_drhoa = -rs/(3.*rho); double dec_local_drhoa = dec_local_rs*drs_drhoa + dec_local_zeta*dzeta_drhoa; od.df_drho_a += limit_df_drhoa(id.a.rho, gamma, ec_local, dec_local_drhoa); } else if (id.b.rho > MIN_DENSITY) { // df_drho_a diverges double dzeta_drhob = 1./rho * (-1. - z); double drs_drhob = -rs/(3.*rho); double dec_local_drhob = dec_local_rs*drs_drhob + dec_local_zeta*dzeta_drhob; od.df_drho_b += limit_df_drhoa(id.b.rho, gamma, ec_local, dec_local_drhob); } double g0,g1,g2,g3,g4,g5,g6,g7,g8,g9,g10,g11,g12,g13,g14,g15,g16,g17,g18 ,g19,g20,g21,g22,g23; g0 = pow(rs,3.0); g1 = pow(c_c0,2.0); g2 = pow(z+1.0,0.66666666666666663)+pow(-(1.0*z)+1.0, 0.66666666666666663); g3 = pow(g2,3.0); g4 = 1/pow(c_c0,1.0); g5 = pow(rs,7.0); g6 = pow(g2,2.0); g7 = 1/g6; g8 = pow(rs,14.0); g9 = 1/pow(g2,4.0); g10 = 1/g1; g11 = exp(-0.064451410964169495*alpha*g10*ec_local*1.0/g3)- 1.0; g12 = 1/pow(g11,1.0); g13 = pow(gamma,3.0); g14 = pow(gamma,2.0); g15 = pow(alpha,2.0); g16 = 1/pow(g11,2.0); g17 = pow(gamma,4.0); g18 = 0.83077810845472067*g15*g10*g8*g9*g16*g17+ 0.91147030036898102*alpha*g4*g5*g7*g12*g14+1.0; g19 = 1/pow(g18,1.0); g20 = 6.5448368524534253*alpha*g4*g8*g9*g12*g17+7.18052672676657 *g5*g7*g14; g21 = pow(rs,2.0); g22 = (0.001*(b*g21+a*rs+2.5680000000000001))/pow(10.0*b*g0+d* g21+c*rs+1.0,1.0)-(1.4285714285714286*c_x)-(1.0*c_c0); g23 = exp(-29.773894288156065*pow(rs,8.0)*g6*g14); dpwc_dg = (0.238732414637843*(-(842.12339075297325*pow(rs,15.0 )*g22*g3*g13*g23)+28.283951793567255*g5*g22*g2*gamma*g23+( 15.515564128703568*g1*g3*(-((0.12693641219540738*alpha*g4*( 3.3231124338188827*g15*g10*g8*g9*g16*g13+1.822940600737962* alpha*g4*g5*g7*g12*gamma)*g20)/pow(g18,2.0))+ 0.12693641219540738*alpha*g4*(26.179347409813701*alpha*g4*g8*g9 *g12*g13+14.36105345353314*g5*g7*gamma)*g19))/pow(alpha,1.0)/ pow(0.12693641219540738*alpha*g4*g19*g20+1.0,1.0)))/g0; od.df_dgamma_aa += dpwc_dg / (2 * gamma); od.df_dgamma_bb += dpwc_dg / (2 * gamma); od.df_dgamma_ab += dpwc_dg / gamma; } od.energy += pwc; } ///////////////////////////////////////////////////////////////////////////// // PW91XFunctional static ClassDesc PW91XFunctional_cd( typeid(PW91XFunctional),"PW91XFunctional",1,"public DenFunctional", 0, create, create); PW91XFunctional::PW91XFunctional(StateIn& s): SavableState(s), DenFunctional(s) { s.get(a); s.get(b); s.get(c); s.get(d); s.get(a_x); } PW91XFunctional::PW91XFunctional() { init_constants(); } PW91XFunctional::PW91XFunctional(const Ref& keyval): DenFunctional(keyval) { init_constants(); a_x = keyval->doublevalue("a_x", KeyValValuedouble(a_x)); a = keyval->doublevalue("a", KeyValValuedouble(a)); b = keyval->doublevalue("b", KeyValValuedouble(b)); c = keyval->doublevalue("c", KeyValValuedouble(c)); d = keyval->doublevalue("d", KeyValValuedouble(d)); } PW91XFunctional::~PW91XFunctional() { } void PW91XFunctional::init_constants() { a = 0.19645; b = 7.7956; c = 0.2743; // the PW91 paper had d = 0.1508 // PBE.f has the following d = 0.15084; // a_x -(3/4)*(3/pi)^(1/3) // the following rounded a_x appears in PBE.f a_x = -0.7385588; } void PW91XFunctional::save_data_state(StateOut& s) { DenFunctional::save_data_state(s); s.put(a); s.put(b); s.put(c); s.put(d); s.put(a_x); } int PW91XFunctional::need_density_gradient() { return 1; } void PW91XFunctional::spin_contrib(const PointInputData::SpinData &i, double &pw, double &dpw_dr, double &dpw_dg) { double rho = i.rho; double gamma = i.gamma; const double pi = M_PI; if (rho < MIN_DENSITY) { pw = 0.; dpw_dr = 0.; dpw_dg = 0.; // really -inf return; } if (gamma < MIN_GAMMA) { double rho_43 = rho * i.rho_13; // rho^(4/3) // 2^(1/3) * a_x * rho^(4/3) pw = 1.2599210498948732 * a_x * rho_43; // (4/3) 2^(1/3) a_x rho^(1/3) dpw_dr = 1.6798947331931642 * a_x * i.rho_13; // (6^(2/3) a_x / (24 3^(1/3) pi^4/3)) (d - c) / rho^(4/3) dpw_dg = - 0.020732388737701564 * a_x * (d - c) / rho_43; return; } // this has been generated by macsyma and modified double t0,t1,t2,t3,t4,t5,t6,t7,t8,t9; t0 = 1.8171205928321397; // pow(6,1.0/3.0); t1 = rho * i.rho_13; // pow(rho,4.0/3.0); t2 = 1/t0; t3 = 0.46619407703541166; // 1/pow(pi,2.0/3.0); t4 = 1/t1; t5 = sqrt(gamma); t6 = (t2*a*t3*t4*asinh((t2*b*t3*t4*t5)/2.0)*t5)/2.0; t7 = 0.30285343213868998; // 1/pow(6,2.0/3.0); t8 = 0.21733691746289932; // 1/pow(pi,4.0/3.0); t9 = t4*t4; // 1/pow(rho,8.0/3.0); pw = (t0*a_x*t1*((t7*t8*t9*gamma*(-(d*exp(-25.0*t7*t8*t9*gamma))+c) )/4.0+t6+1))/pow(3,1.0/3.0)/((t2*pow(gamma,2.0))/24000.0/pow(pi,8.0 /3.0)/pow(rho,16.0/3.0)+t6+1); if (compute_potential_) { double r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,r13,r14,r15,r16,r17,r18 ,r19,r20,r21,r22; r0 = 0.69336127435063466; // 1/pow(3,1.0/3.0); r1 = t0; // pow(6,1.0/3.0); r2 = t1; // pow(rho,4.0/3.0); r3 = 1/r1; r4 = t3; // 1/pow(pi,2.0/3.0); r5 = 1/r2; r6 = t5; // sqrt(gamma); r7 = asinh((r3*b*r4*r5*r6)/2.0); r8 = (r3*a*r4*r5*r7*r6)/2.0; r9 = 1/pow(pi,8.0/3.0); r10 = gamma*gamma; // pow(gamma,2.0); r11 = (r3*r9*r10)/24000.0/pow(rho,16.0/3.0)+r8+1; r12 = 1/r11; r13 = -((2.0/3.0*r3*a*r4*r7*r6)/pow(rho,7.0/3.0)); r14 = 1/pow(6,2.0/3.0); r15 = 1/pow(pi,4.0/3.0); r16 = 1/pow(rho,11.0/3.0); r17 = 1/pow(rho,8.0/3.0); r18 = -((1.0/3.0*r14*a*b*r15*r16*gamma)/sqrt((r14*pow(b,2.0)*r15*r17 *gamma)/4.0+1)); r19 = 1/pow(rho,19.0/3.0); r20 = exp(-25.0*r14*r15*r17*gamma); r21 = -(d*r20)+c; r22 = (r14*r15*r17*gamma*r21)/4.0+r8+1; dpw_dr = -((r0*r1*a_x*r2*(r18-(1.0/4500.0*r3*r9*r19*r10)+r13)*r22)/ pow(r11,2.0))+4.0/3.0*r0*r1*a_x*pow(rho,1.0/3.0)*r12*r22+r0*r1*a_x* r2*r12*(-(2.0/3.0*r14*r15*r16*gamma*r21)-(25.0/9.0*r3*d*r9*r19*r10* r20)+r18+r13); double g0,g1,g2,g3,g4,g5,g6,g7,g8,g9,g10,g11,g12,g13,g14,g15,g16,g17,g18; g0 = 1/pow(3,1.0/3.0); g1 = pow(6,1.0/3.0); g2 = pow(rho,4.0/3.0); g3 = 1/g1; g4 = 1/pow(pi,2.0/3.0); g5 = 1/g2; g6 = sqrt(gamma); g7 = asinh((g3*b*g4*g5*g6)/2.0); g8 = (g3*a*g4*g5*g7*g6)/2.0; g9 = 1/pow(pi,8.0/3.0); g10 = 1/pow(rho,16.0/3.0); g11 = (g3*g9*g10*pow(gamma,2.0))/24000.0+g8+1; g12 = (g3*a*g4*g5*g7)/4.0/g6; g13 = 1/pow(6,2.0/3.0); g14 = 1/pow(pi,4.0/3.0); g15 = 1/pow(rho,8.0/3.0); g16 = (g13*a*b*g14*g15)/8.0/sqrt((g13*pow(b,2.0)*g14*g15*gamma)/4.0+ 1); g17 = exp(-25.0*g13*g14*g15*gamma); g18 = -(d*g17)+c; dpw_dg = -((g0*g1*a_x*g2*(g16+(g3*g9*g10*gamma)/12000.0+g12)*((g13* g14*g15*gamma*g18)/4.0+g8+1))/pow(g11,2.0))+(g0*g1*a_x*g2*((g13*g14 *g15*g18)/4.0+25.0/24.0*g3*d*g9*g10*gamma*g17+g16+g12))/g11; } } void PW91XFunctional::point(const PointInputData &id, PointOutputData &od) { od.zero(); double mpw, dmpw_dr, dmpw_dg; // alpha spin_contrib(id.a, mpw, dmpw_dr, dmpw_dg); od.energy = mpw; od.df_drho_a = dmpw_dr; od.df_dgamma_aa = dmpw_dg; // beta if (spin_polarized_) { spin_contrib(id.b, mpw, dmpw_dr, dmpw_dg); od.energy += mpw; od.df_drho_b = dmpw_dr; od.df_dgamma_bb = dmpw_dg; } else { od.energy += mpw; od.df_drho_b = od.df_drho_a; od.df_dgamma_bb = od.df_dgamma_aa; } } ///////////////////////////////////////////////////////////////////////////// // PBEXFunctional static ClassDesc PBEXFunctional_cd( typeid(PBEXFunctional),"PBEXFunctional",1,"public DenFunctional", 0, create, create); PBEXFunctional::PBEXFunctional(StateIn& s): SavableState(s), DenFunctional(s) { s.get(mu); s.get(kappa); } PBEXFunctional::PBEXFunctional() { init_constants(); } PBEXFunctional::PBEXFunctional(const Ref& keyval): DenFunctional(keyval) { init_constants(); mu = keyval->doublevalue("mu", KeyValValuedouble(mu)); kappa = keyval->doublevalue("kappa", KeyValValuedouble(kappa)); if (keyval->booleanvalue("revPBE")) { kappa = 1.245; } } PBEXFunctional::~PBEXFunctional() { } void PBEXFunctional::init_constants() { // in paper: // mu = 0.21951; // in PBE.F mu = 0.2195149727645171; kappa = 0.804; } void PBEXFunctional::save_data_state(StateOut& s) { DenFunctional::save_data_state(s); s.put(mu); s.put(kappa); } int PBEXFunctional::need_density_gradient() { return 1; } void PBEXFunctional::spin_contrib(const PointInputData::SpinData &i, double &pbex, double &dpbex_drhoa, double &dpbex_dgaa) { double rhoa = i.rho; double rhoa_13 = i.rho_13; double rhoa_43 = rhoa*rhoa_13; double gaa = i.gamma; if (rhoa < MIN_DENSITY) { pbex = 0; if (compute_potential_) { dpbex_drhoa = 0.0; dpbex_dgaa = 0.0; // really -inf } return; } if (gaa < MIN_GAMMA) { pbex = - 0.93052573634910019 * rhoa_43; if (compute_potential_) { dpbex_drhoa = -(1.2407009817988002*rhoa_13); dpbex_dgaa = -((0.015312087450269402*mu)/rhoa_43); } return; } double rhoa_83 = rhoa_43*rhoa_43; pbex = -(0.93052573634910007*(-(kappa/(( 0.016455307846020562*gaa*mu)/kappa/rhoa_83+1.0))+kappa+1.0)*rhoa_43); if (compute_potential_) { double rhoa_73 = rhoa_43*rhoa; double r0; r0 = (0.016455307846020562*gaa*mu)/kappa/rhoa_83+1.0; dpbex_drhoa = -(1.2407009817988002*(-(kappa/r0) +kappa+1.0)*rhoa_13)+(0.040832233200718403*gaa*mu)/(r0*r0)/rhoa_73; dpbex_dgaa = -((0.015312087450269402*mu)/(r0*r0)/rhoa_43); } } void PBEXFunctional::point(const PointInputData &id, PointOutputData &od) { od.zero(); double pbex, dpbex_dr, dpbex_dg; // alpha spin_contrib(id.a, pbex, dpbex_dr, dpbex_dg); od.energy = pbex; if (compute_potential_) { od.df_drho_a = dpbex_dr; od.df_dgamma_aa = dpbex_dg; } // beta if (spin_polarized_) { spin_contrib(id.b, pbex, dpbex_dr, dpbex_dg); od.energy += pbex; if (compute_potential_) { od.df_drho_b = dpbex_dr; od.df_dgamma_bb = dpbex_dg; } } else { od.energy += pbex; if (compute_potential_) { od.df_drho_b = od.df_drho_a; od.df_dgamma_bb = od.df_dgamma_aa; } } } ///////////////////////////////////////////////////////////////////////////// // mPW91XFunctional static ClassDesc mPW91XFunctional_cd( typeid(mPW91XFunctional),"mPW91XFunctional",1,"public DenFunctional", 0, create, create); mPW91XFunctional::mPW91XFunctional(StateIn& s): SavableState(s), DenFunctional(s) { init_constants(mPW91); s.get(b); s.get(beta); s.get(c); s.get(d); s.get(x_d_coef); } mPW91XFunctional::mPW91XFunctional() { init_constants(mPW91); } mPW91XFunctional::mPW91XFunctional(mPW91XFunctional::Func f) { init_constants(f); } mPW91XFunctional::mPW91XFunctional(const Ref& keyval): DenFunctional(keyval) { char *t = keyval->pcharvalue("constants"); if (t) { if (!strcmp(t,"B88")) { init_constants(B88); } else if (!strcmp(t,"PW91")) { init_constants(PW91); } else if (!strcmp(t,"mPW91")) { init_constants(mPW91); } else { ExEnv::outn() << "mPW91XFunctional: bad \"constants\": " << t << endl; abort(); } delete[] t; } else { init_constants(mPW91); } b = keyval->doublevalue("b", KeyValValuedouble(b)); beta = keyval->doublevalue("beta", KeyValValuedouble(beta)); c = keyval->doublevalue("c", KeyValValuedouble(c)); d = keyval->doublevalue("d", KeyValValuedouble(d)); x_d_coef = keyval->doublevalue("x_d_coef", KeyValValuedouble(x_d_coef)); } mPW91XFunctional::~mPW91XFunctional() { } void mPW91XFunctional::init_constants(Func f) { a_x = -1.5*pow(3./(4.*M_PI), 1./3.); if (f == B88) { b = 0.0042; beta = 0.0042; c = 0.; d = 1.; x_d_coef = 0.; } else if (f == PW91) { b = 0.0042; beta = 5.*pow(36.*M_PI,-5./3.); c = 1.6455; d = 4.; x_d_coef = 1.e-6; } else { b = 0.0046; beta = 5.*pow(36.*M_PI,-5./3.); c = 1.6455; d = 3.73; x_d_coef = 1.e-6; } } void mPW91XFunctional::save_data_state(StateOut& s) { DenFunctional::save_data_state(s); s.put(b); s.put(beta); s.put(c); s.put(d); s.put(x_d_coef); } int mPW91XFunctional::need_density_gradient() { return 1; } void mPW91XFunctional::spin_contrib(const PointInputData::SpinData &i, double &mpw, double &dmpw_dr, double &dmpw_dg) { // this has been generated by macsyma double rho = i.rho; double gamma = i.gamma; if (rho < MIN_DENSITY) { mpw = 0.; dmpw_dr = 0.; dmpw_dg = 0.; // division by zero return; } if (gamma < MIN_GAMMA) { double rho_43 = rho * i.rho_13; // rho^(4/3) // 2^(1/3) * a_x * rho^(4/3) mpw = a_x * rho_43; // (4/3) a_x rho^(1/3) dmpw_dr = (4./3.) * a_x * i.rho_13; dmpw_dg = -beta/rho_43; return; } double t0,t1,t2,t3,t4,t5; t0 = pow(rho,4.0/3.0); t1 = 1/t0; t2 = sqrt(gamma); t3 = 1/pow(rho,4.0/3.0*d); t4 = pow(gamma,d/2.0); t5 = 1/pow(rho,8.0/3.0); mpw = t0*(-((-(((-beta+b)*t5*gamma)*exp(-c*t5*gamma))-(t3*x_d_coef*t4 )+b*t5*gamma)/(-((t3*x_d_coef*t4)/a_x)+6*b*t1*asinh(t1*t2)*t2+1))+ a_x); if (compute_potential_) { double r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,r13,r14; r0 = pow(rho,4.0/3.0); r1 = 1/r0; r2 = sqrt(gamma); r3 = asinh(r1*r2); r4 = 1/a_x; r5 = 1/pow(rho,4.0/3.0*d); r6 = pow(gamma,d/2.0); r7 = -(r4*r5*x_d_coef*r6)+6*b*r1*r3*r2+1; r8 = 1/r7; r9 = 1/pow(rho,8.0/3.0); r10 = -beta+b; r11 = exp(-c*r9*gamma); r12 = -(r10*r9*gamma*r11)-(r5*x_d_coef*r6)+b*r9*gamma; r13 = 1/pow(rho,11.0/3.0); r14 = pow(rho,-(4.0/3.0*d)-1); dmpw_dr = r0*(-(r8*(-((8.0/3.0*r10*c*pow(gamma,2.0)*r11)/pow(rho, 19.0/3.0))+8.0/3.0*r10*r13*gamma*r11+4.0/3.0*d*r14*x_d_coef*r6-(8.0 /3.0*b*r13*gamma)))+((4.0/3.0*r4*d*r14*x_d_coef*r6-((8*b*r13*gamma) /sqrt(r9*gamma+1))-((8*b*r3*r2)/pow(rho,7.0/3.0)))*r12)/pow(r7,2.0) )+4.0/3.0*pow(rho,1.0/3.0)*(-(r8*r12)+a_x); double g0,g1,g2,g3,g4,g5,g6,g7,g8,g9,g10,g11,g12; g0 = pow(rho,4.0/3.0); g1 = 1/g0; g2 = sqrt(gamma); g3 = asinh(g1*g2); g4 = 1/a_x; g5 = 1/pow(rho,4.0/3.0*d); g6 = d/2.0; g7 = pow(gamma,g6); g8 = -(g4*g5*x_d_coef*g7)+6*b*g1*g3*g2+1; g9 = 1/pow(rho,8.0/3.0); g10 = pow(gamma,g6-1); g11 = -beta+b; g12 = exp(-c*g9*gamma); dmpw_dg = g0*(((-(1.0/2.0*g4*d*g5*x_d_coef*g10)+(3*b*g9)/sqrt(g9* gamma+1)+(3*b*g1*g3)/g2)*(-(g11*g9*gamma*g12)-(g5*x_d_coef*g7)+b*g9 *gamma))/pow(g8,2.0)-(((g11*c*gamma*g12)/pow(rho,16.0/3.0)-(g11*g9* g12)-(1.0/2.0*d*g5*x_d_coef*g10)+b*g9)/g8)); } } void mPW91XFunctional::point(const PointInputData &id, PointOutputData &od) { od.zero(); double mpw, dmpw_dr, dmpw_dg; // alpha spin_contrib(id.a, mpw, dmpw_dr, dmpw_dg); od.energy = mpw; od.df_drho_a = dmpw_dr; od.df_dgamma_aa = dmpw_dg; // beta if (spin_polarized_) { spin_contrib(id.b, mpw, dmpw_dr, dmpw_dg); od.energy += mpw; od.df_drho_b = dmpw_dr; od.df_dgamma_bb = dmpw_dg; } else { od.energy += mpw; od.df_drho_b = od.df_drho_a; od.df_dgamma_bb = od.df_dgamma_aa; } } ///////////////////////////////////////////////////////////////////////////// // Perdew-Wang (PW86) Exchange Functional // J. P. Perdew and Y. Wang, Phys. Rev. B, 33, 8800, 1986. // // Coded by Matt Leininger static ClassDesc PW86XFunctional_cd( typeid(PW86XFunctional),"PW86XFunctional",1,"public DenFunctional", 0, create, create); PW86XFunctional::PW86XFunctional(StateIn& s): SavableState(s), DenFunctional(s) { s.get(m_); s.get(a_); s.get(b_); s.get(c_); } PW86XFunctional::PW86XFunctional() { init_constants(); } PW86XFunctional::PW86XFunctional(const Ref& keyval): DenFunctional(keyval) { init_constants(); m_ = keyval->doublevalue("m", KeyValValuedouble(m_)); a_ = keyval->doublevalue("a", KeyValValuedouble(a_)); b_ = keyval->doublevalue("b", KeyValValuedouble(b_)); c_ = keyval->doublevalue("c", KeyValValuedouble(c_)); } PW86XFunctional::~PW86XFunctional() { } void PW86XFunctional::save_data_state(StateOut& s) { DenFunctional::save_data_state(s); s.put(m_); s.put(a_); s.put(b_); s.put(c_); } void PW86XFunctional::init_constants() { m_ = 1./15.; a_ = 0.0864/m_; b_ = 14.; c_ = 0.2; } int PW86XFunctional::need_density_gradient() { return 1; } void PW86XFunctional::point(const PointInputData &id, PointOutputData &od) { od.zero(); double rhoa = 2. * id.a.rho; double k_fa = pow( (3.*M_PI*M_PI*rhoa), (1./3.) ); double rhoa43 = pow(rhoa, (4./3.)); double rhoa13 = pow(rhoa, (1./3.)); double Ax = -3./4.*pow( (3./M_PI), (1./3.) ); double gamma_aa = 2. * sqrt(id.a.gamma); double sa; if (rhoa < MIN_DENSITY) sa = 0.; else sa = gamma_aa/(2. * k_fa * rhoa); double sa2 = sa*sa; double sa3 = sa2*sa; double sa4 = sa2*sa2; double sa5 = sa4*sa; double sa6 = sa5*sa; double F1a = 1. + a_*sa2 + b_*sa4 + c_*sa6; double Fxa = pow(F1a, m_); double fpw86xa = Ax * rhoa43 * Fxa; double ex = 0.5 * fpw86xa; if (compute_potential_) { double dsa_drhoa; if (rhoa < MIN_DENSITY) dsa_drhoa = 0.; else dsa_drhoa = -4.*2.*sa/(3.*rhoa); double dFxa_drhoa = m_ * pow(F1a, (m_-1.)) * ( 2.*a_*sa + 4.*b_*sa3 + 6.*c_*sa5) * dsa_drhoa; double dfpw86xa_drhoa = Ax * ( 2.*4./3.*rhoa13*Fxa + rhoa43 * dFxa_drhoa ); od.df_drho_a = 0.5 * dfpw86xa_drhoa; double sa_dsa_dgamma_aa; if (rhoa < MIN_DENSITY) sa_dsa_dgamma_aa = 0.; else { sa_dsa_dgamma_aa = 2./pow( (2.*k_fa*rhoa), 2.); } double dFxa_dgamma_aa = m_ * pow(F1a, (m_-1.)) * ( 2.*a_ + 4.*b_*sa2 + 6.*c_*sa4 ) * sa_dsa_dgamma_aa ; double dfpw86xa_dgamma_aa = Ax * rhoa43 * dFxa_dgamma_aa; od.df_dgamma_aa = 0.5 * dfpw86xa_dgamma_aa; od.df_drho_b = od.df_drho_a; od.df_dgamma_bb = od.df_dgamma_aa; od.df_dgamma_ab = 0.; } if (spin_polarized_) { double rhob = 2. * id.b.rho; double k_fb = pow( (3.*M_PI*M_PI*rhob), (1./3.) ); double rhob43 = pow(rhob, (4./3.)); double rhob13 = pow(rhob, (1./3.)); double gamma_bb = 2.*sqrt(id.b.gamma); double sb; if (rhob < MIN_DENSITY) sb = 0.; else sb = gamma_bb/(2.*k_fb*rhob); double sb2 = sb*sb; double sb3 = sb2*sb; double sb4 = sb3*sb; double sb5 = sb4*sb; double sb6 = sb5*sb; double F1b = 1. + a_*sb2 + b_*sb4 + c_*sb6; double Fxb = pow(F1b, m_); double fpw86xb = Ax * rhob43 * Fxb; ex += 0.5 * fpw86xb; if (compute_potential_) { double dsb_drhob; if (rhob < MIN_DENSITY) dsb_drhob = 0.; else dsb_drhob = -4.*2.*sb/(3.*rhob); double dFxb_drhob = m_ * pow(F1b, (m_-1.)) * (2.*a_*sb + 4.*b_*sb3 + 6.*c_*sb5) * dsb_drhob; double dfpw86xb = Ax * ( 2.*4./3.*rhob13*Fxb + rhob43 * dFxb_drhob ); od.df_drho_b = 0.5 * dfpw86xb; double sb_dsb_dgamma_bb; if (rhob < MIN_DENSITY) sb_dsb_dgamma_bb = 0.; else { sb_dsb_dgamma_bb = 2./pow( (2.*k_fb*rhob), 2.); } double dFxb_dgamma_bb = m_ * pow(F1b, (m_-1.)) * ( 2.*a_ + 4.*b_*sb2 + 6.*c_*sb4) * sb_dsb_dgamma_bb; double dfpw86xb_dgamma_bb = Ax * rhob43 * dFxb_dgamma_bb; od.df_dgamma_bb = 0.5 * dfpw86xb_dgamma_bb; } } else ex += ex; od.energy = ex; } ///////////////////////////////////////////////////////////////////////////// // Gill 1996 (G96) Exchange Functional // P. M. W. Gill, Mol. Phys. 89, 433, 1996. // // Coded by Matt Leininger static ClassDesc G96XFunctional_cd( typeid(G96XFunctional),"G96XFunctional",1,"public DenFunctional", 0, create, create); G96XFunctional::G96XFunctional(StateIn& s): SavableState(s), DenFunctional(s) { s.get(b_); } G96XFunctional::G96XFunctional() { init_constants(); } G96XFunctional::G96XFunctional(const Ref& keyval): DenFunctional(keyval) { init_constants(); b_ = keyval->doublevalue("b", KeyValValuedouble(b_)); } G96XFunctional::~G96XFunctional() { } void G96XFunctional::save_data_state(StateOut& s) { DenFunctional::save_data_state(s); s.put(b_); } void G96XFunctional::init_constants() { b_ = 1./137.; } int G96XFunctional::need_density_gradient() { return 1; } void G96XFunctional::point(const PointInputData &id, PointOutputData &od) { od.zero(); double rhoa = id.a.rho; double rhoa43 = pow(rhoa, (4./3.)); double rhoa13 = pow(rhoa, (1./3.)); double gamma_aa = sqrt(id.a.gamma); double gamma_aa32 = pow(gamma_aa, 1.5); double alpha = -1.5 * pow( (3./(4.*M_PI)), (1./3.) ); double gg96a; double fxg96a; if (rhoa < MIN_DENSITY) gg96a = fxg96a = 0.; else { gg96a = alpha - b_*gamma_aa32/(rhoa*rhoa); fxg96a = rhoa43 * gg96a; } double ex = fxg96a; if (compute_potential_) { double dfxg96a_drhoa; if (rhoa < MIN_DENSITY) dfxg96a_drhoa = 0.; else { double dgg96a_drhoa = 2.*b_*gamma_aa32/(rhoa*rhoa*rhoa); dfxg96a_drhoa = 4./3.*rhoa13*gg96a + rhoa43*dgg96a_drhoa; } od.df_drho_a = dfxg96a_drhoa; od.df_drho_b = od.df_drho_a; double dfxg96a_dgamma_aa; // The derivative of the G96X functional with respect to gamma_aa or bb // as implemented should go to infinity as gamma goes to zero. // However, the derivative gamma terms are eventually contracted with quantities // that have a sqrt(gamma) in the numerator and therefore the overall limit // is zero. if (gamma_aa < MIN_GAMMA || rhoa < MIN_DENSITY ) dfxg96a_dgamma_aa = 0.; else { double dgg96a_dgamma_aa = -3.*b_ / ( 4.*rhoa*rhoa*sqrt(gamma_aa) ); dfxg96a_dgamma_aa = rhoa43 * dgg96a_dgamma_aa; } od.df_dgamma_aa = dfxg96a_dgamma_aa; od.df_dgamma_bb = od.df_dgamma_aa; od.df_dgamma_ab = 0.; } if (spin_polarized_) { double rhob = id.b.rho; double rhob43 = pow(rhob, (4./3.)); double rhob13 = pow(rhob, (1./3.)); double gamma_bb = sqrt(id.b.gamma); double gamma_bb32 = pow(gamma_bb, 1.5); double gg96b; double fxg96b; if (rhob < MIN_DENSITY) gg96b = fxg96b = 0.; else { gg96b = alpha - b_*gamma_bb32/(rhob*rhob); fxg96b = rhob43 * gg96b; } ex += fxg96b; if (compute_potential_) { double dfxg96b_drhob; if (rhob < MIN_DENSITY) dfxg96b_drhob = 0.; else { double dgg96b_drhob = 2.*b_*gamma_bb32/(rhob*rhob*rhob); dfxg96b_drhob = 4./3.*rhob13*gg96b + rhob43*dgg96b_drhob; } od.df_drho_b = dfxg96b_drhob; double dfxg96b_dgamma_bb; // See comment above with regard to correct limits. if (gamma_bb < MIN_GAMMA || rhob < MIN_DENSITY) dfxg96b_dgamma_bb=0.; else { double dgg96b_dgamma_bb = -3.*b_ / (4.*rhob*rhob*sqrt(gamma_bb)); dfxg96b_dgamma_bb = rhob43 * dgg96b_dgamma_bb; } od.df_dgamma_bb = dfxg96b_dgamma_bb; } } else ex += ex; od.energy = ex; } ///////////////////////////////////////////////////////////////////////////// // Local Variables: // mode: c++ // c-file-style: "CLJ" // End: