//////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2008 The Regents of the University of California // // This file is part of Qbox // // Qbox is distributed under the terms of the GNU General Public License // as published by the Free Software Foundation, either version 2 of // the License, or (at your option) any later version. // See the file COPYING in the root directory of this distribution // or . // //////////////////////////////////////////////////////////////////////////////// // // Preconditioner.C // //////////////////////////////////////////////////////////////////////////////// #include "Preconditioner.h" #include "Basis.h" #include "Wavefunction.h" #include "EnergyFunctional.h" #include "ConfinementPotential.h" #include "SlaterDet.h" using namespace std; //////////////////////////////////////////////////////////////////////////////// Preconditioner::Preconditioner(const Wavefunction& wf, EnergyFunctional& ef, double ecutprec) : ef_(ef), ecutprec_(ecutprec) { kpg2_.resize(wf.nspin()); ekin_.resize(wf.nspin()); for ( int ispin = 0; ispin < wf.nspin(); ispin++ ) { kpg2_[ispin].resize(wf.nkp()); ekin_[ispin].resize(wf.nkp()); for ( int ikp = 0; ikp < wf.nkp(); ikp++ ) { const SlaterDet& sd = *(wf.sd(ispin,ikp)); const Basis& wfbasis = sd.basis(); kpg2_[ispin][ikp] = wfbasis.kpg2_ptr(); ekin_[ispin][ikp].resize(sd.nstloc()); } } update(wf); } //////////////////////////////////////////////////////////////////////////////// double Preconditioner::diag(int ispin, int ikp, int n, int ig) const { const valarray& fstress = ef_.confpot(ikp)->fstress(); if ( ecutprec_ == 0.0 ) { double ekin_n = ekin_[ispin][ikp][n]; // if ekin_n == 0 (occurs for first wf, G=0, when starting without // randomizing wfs) replace ekin_n by fixed value 1.0 if ( ekin_n == 0.0 ) ekin_n = 1.0; const double q2 = kpg2_[ispin][ikp][ig] + fstress[ig]; #if 0 #if 0 // Payne Teter Allan adaptive preconditioner const double x = 0.5 * q2 / ekin_n; const double num = 27.0 + x * ( 18.0 + x * ( 12 + x * 8 )); const double den = num + 16.0 * x*x*x*x; return (num/den); #else // modified Payne Teter Allan adaptive preconditioner (Kresse) const double x = 0.5 * q2 / ( 1.5 * ekin_n ); const double num = 27.0 + x * ( 18.0 + x * ( 12 + x * 8 )); const double den = num + 16.0 * x*x*x*x; return ( 2.0 / (1.5 * ekin_n )) * (num/den); #endif #else // basic adaptive preconditioner: use ekin_n for the value of ecutprec double e = 0.5 * ( kpg2_[ispin][ikp][ig] + fstress[ig] ); return ( e < ekin_n ) ? 0.5 / ekin_n : 0.5 / e; #endif } else { double e = 0.5 * ( kpg2_[ispin][ikp][ig] + fstress[ig] ); return ( e < ecutprec_ ) ? 0.5 / ecutprec_ : 0.5 / e; } } //////////////////////////////////////////////////////////////////////////////// void Preconditioner::update(const Wavefunction& wf) { // update the kinetic energy ekin_[ispin][ikp][n] of states in wf for ( int ispin = 0; ispin < wf.nspin(); ispin++ ) { for ( int ikp = 0; ikp < wf.nkp(); ikp++ ) { const SlaterDet& sd = *(wf.sd(ispin,ikp)); const Basis& wfbasis = sd.basis(); // factor fac in next lines: 2.0 for G and -G (if basis is real) const double fac = wfbasis.real() ? 2.0 : 1.0; const ComplexMatrix& c = sd.c(); const Context& sdctxt = sd.context(); const int ngwloc = wfbasis.localsize(); const complex* p = c.cvalptr(); const int mloc = c.mloc(); const int nloc = c.nloc(); valarray buf(2*nloc); const double* pkpg2 = kpg2_[ispin][ikp]; for ( int n = 0; n < nloc; n++ ) { double sum_norm = 0.0; double sum_ekin = 0.0; for ( int ig = 0; ig < ngwloc; ig++ ) { const double psi2 = norm(p[ig+n*mloc]); sum_norm += psi2; sum_ekin += psi2 * pkpg2[ig]; } // correct for double counting of G=0 in norm if ( sdctxt.myrow() == 0 ) sum_norm -= 0.5 * norm(p[n*mloc]); // store norm in buf[n] and ekin in buf[n+nloc] buf[n] = fac * sum_norm; buf[n+nloc] = fac * sum_ekin; } sdctxt.dsum('C',2*nloc,1,&buf[0],2*nloc); // factor 0.5 in next line: 1/(2m) for ( int n = 0; n < nloc; n++ ) ekin_[ispin][ikp][n] = 0.5*buf[n] > 0.0 ? 0.5*buf[n+nloc]/buf[n] : 0; #ifdef DEBUG if ( sdctxt.onpe0() ) { for ( int n = 0; n < nloc; n++ ) cout << "Preconditioner::update ekin[" << n << "] = " << ekin_[ispin][ikp][n] << endl; } #endif } } }