////////////////////////////////////////////////////////////////////////////////
//
// 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 .
//
////////////////////////////////////////////////////////////////////////////////
//
// PSDWavefunctionStepper.C
//
////////////////////////////////////////////////////////////////////////////////
#include "PSDWavefunctionStepper.h"
#include "Wavefunction.h"
#include "SlaterDet.h"
#include "Preconditioner.h"
#include
using namespace std;
////////////////////////////////////////////////////////////////////////////////
PSDWavefunctionStepper::PSDWavefunctionStepper(Wavefunction& wf,
Preconditioner& prec, TimerMap& tmap) : WavefunctionStepper(wf,tmap),
prec_(prec)
{}
////////////////////////////////////////////////////////////////////////////////
PSDWavefunctionStepper::~PSDWavefunctionStepper(void)
{}
////////////////////////////////////////////////////////////////////////////////
void PSDWavefunctionStepper::update(Wavefunction& dwf)
{
for ( int ispin = 0; ispin < wf_.nspin(); ispin++ )
{
for ( int ikp = 0; ikp < wf_.nkp(); ikp++ )
{
// compute A = V^T H V and descent direction HV - VA
tmap_["psd_residual"].start();
if ( wf_.sd(ispin,ikp)->basis().real() )
{
// proxy real matrices c, cp
DoubleMatrix c(wf_.sd(ispin,ikp)->c());
DoubleMatrix cp(dwf.sd(ispin,ikp)->c());
DoubleMatrix a(c.context(),c.n(),c.n(),c.nb(),c.nb());
// factor 2.0 in next line: G and -G
a.gemm('t','n',2.0,c,cp,0.0);
// rank-1 update correction
a.ger(-1.0,c,0,cp,0);
// cp = cp - c * a
cp.gemm('n','n',-1.0,c,a,1.0);
}
else
{
ComplexMatrix& c = wf_.sd(ispin,ikp)->c();
ComplexMatrix& cp = dwf.sd(ispin,ikp)->c();
ComplexMatrix a(c.context(),c.n(),c.n(),c.nb(),c.nb());
a.gemm('c','n',1.0,c,cp,0.0);
// cp = cp - c * a
cp.gemm('n','n',-1.0,c,a,1.0);
}
tmap_["psd_residual"].stop();
}
}
// dwf.sd->c() now contains the descent direction (HV-VA)
// update preconditioner using the residual
prec_.update(dwf);
for ( int ispin = 0; ispin < wf_.nspin(); ispin++ )
{
for ( int ikp = 0; ikp < wf_.nkp(); ikp++ )
{
tmap_["psd_update_wf"].start();
double* coeff = (double*) wf_.sd(ispin,ikp)->c().valptr();
const double* dcoeff =
(const double*) dwf.sd(ispin,ikp)->c().cvalptr();
const int mloc = wf_.sd(ispin,ikp)->c().mloc();
const int ngwl = wf_.sd(ispin,ikp)->basis().localsize();
const int nloc = wf_.sd(ispin,ikp)->c().nloc();
for ( int n = 0; n < nloc; n++ )
{
// note: double mloc length for complex indices
double* c = &coeff[2*mloc*n];
const double* dc = &dcoeff[2*mloc*n];
for ( int i = 0; i < ngwl; i++ )
{
const double fac = prec_.diag(ispin,ikp,n,i);
const double delta_re = fac * dc[2*i];
const double delta_im = fac * dc[2*i+1];
c[2*i] -= delta_re;
c[2*i+1] -= delta_im;
}
}
tmap_["psd_update_wf"].stop();
tmap_["gram"].start();
wf_.sd(ispin,ikp)->gram();
tmap_["gram"].stop();
}
}
}