00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include "QMCPotential_Energy.h"
00014 #include "Lebedev-Laikov.h"
00015 #include "QMCBasisFunction.h"
00016 #include "MathFunctions.h"
00017 #include "QMCJastrowElectronElectron.h"
00018 #include "QMCJastrowElectronNuclear.h"
00019 #include "QMCThreeBodyJastrow.h"
00020 #include "Stopwatch.h"
00021
00022 QMCPotential_Energy::QMCPotential_Energy()
00023 {}
00024
00025 void QMCPotential_Energy::operator=( const QMCPotential_Energy & rhs )
00026 {
00027 Energy_total = rhs.Energy_total ;
00028 Energy_ne = rhs.Energy_ne;
00029 Energy_ee = rhs.Energy_ee;
00030
00031 Input = rhs.Input;
00032 HartreeFock = rhs.HartreeFock;
00033 WF = rhs.WF;
00034 MOL = rhs.MOL;
00035 wd = 0;
00036
00037 ElectronNucleusCuspA = rhs.ElectronNucleusCuspA;
00038 ElectronNucleusCuspB = rhs.ElectronNucleusCuspB;
00039
00040 P_nn = rhs.P_nn;
00041 P_en = rhs.P_en;
00042 P_ee = rhs.P_ee;
00043 }
00044
00045 void QMCPotential_Energy::initialize(QMCInput * Ip, QMCHartreeFock * HF)
00046 {
00047 Input = Ip;
00048 HartreeFock = HF;
00049 wd = 0;
00050 WF = &Input->WF;
00051 MOL = &Input->Molecule;
00052
00053 Energy_total.allocate(globalInput.flags.walkers_per_pass);
00054 Energy_ne.allocate(globalInput.flags.walkers_per_pass);
00055 Energy_ee.allocate(globalInput.flags.walkers_per_pass);
00056
00057 calc_P_nn();
00058
00059 if (globalInput.flags.replace_electron_nucleus_cusps == 1)
00060 {
00061 coeffs = WF->getCoeff(true);
00062 ElectronNucleusCuspA.initialize(Input, * coeffs);
00063 ElectronNucleusCuspA.fitReplacementOrbitals();
00064 coeffs = WF->getCoeff(false);
00065 ElectronNucleusCuspB.initialize(Input, * coeffs);
00066 ElectronNucleusCuspB.fitReplacementOrbitals();
00067 }
00068
00069 int numN = MOL->Atom_Positions.dim1();
00070 angularGrids.allocate(numN);
00071 for(int nuc=0; nuc<numN; nuc++)
00072 if(MOL->usesPsuedo(nuc))
00073 {
00074 Array2D<double> grTemp = MOL->getGrid(nuc,1.0,false);
00075 globalInput.BF.angularGrid(grTemp,nuc,angularGrids(nuc));
00076 }
00077 }
00078
00079 double QMCPotential_Energy::evaluatePsuedoPotential(Array2D<double> & R, int elec, int nuc)
00080 {
00081 bool isAlpha;
00082 int elecIndex;
00083 double r = wd->riA(elec,nuc);
00084 int lmax = (MOL->gridLegendre(nuc)).dim1();
00085
00086 Array1D<double> vnl(lmax);
00087 Array1D<double> integral(lmax);
00088
00089
00090
00091
00092
00093 double Vlocal = MOL->evaluatePotential(MOL->Vlocal(nuc),r);
00094 Vlocal -= MOL->Zeff(nuc) / r;
00095
00096 bool small = true;
00097 for(int l=0; l<lmax; l++)
00098 {
00099 vnl(l) = MOL->evaluatePotential((MOL->Vnonlocal(nuc))(l),r);
00100 if(fabs(vnl(l)) > globalInput.flags.psuedo_cutoff) small = false;
00101 }
00102
00103
00104 if(small) return Vlocal;
00105
00106 if(elec < WF->getNumberElectrons(true))
00107 {
00108 isAlpha = true;
00109 elecIndex = elec;
00110 Dc_inv = wd->Dc_invA;
00111 } else {
00112 isAlpha = false;
00113 elecIndex = elec - WF->getNumberElectrons(true);
00114 Dc_inv = wd->Dc_invB;
00115 }
00116
00117
00118
00119
00120
00121 Array2D<double> grid = MOL->getGrid(nuc,r,true);
00122
00123 int grSize = grid.dim1();
00124 X.allocate(grSize,WF->getNumberBasisFunctions());
00125 D.allocate(grSize,WF->getNumberOrbitals(isAlpha));
00126 ciDet.allocate(grSize,WF->getNumberElectrons(isAlpha));
00127 integrand.allocate(grSize);
00128 X.allocate(grSize,WF->getNumberBasisFunctions());
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154 globalInput.BF.basisFunctionsOnGrid(grid,nuc,angularGrids(nuc),X);
00155 X.gemm(*WF->getCoeff(isAlpha),D,true);
00156
00157 if (globalInput.flags.replace_electron_nucleus_cusps == 1)
00158 if(isAlpha)
00159 ElectronNucleusCuspA.replaceCusps(grid,0,D.dim1()-1,D);
00160 else
00161 ElectronNucleusCuspB.replaceCusps(grid,0,D.dim1()-1,D);
00162
00163 integrand = 0.0;
00164 double ratio = 1.0;
00165 double psi = 0.0;
00166 for(int ci=0; ci<WF->getNumberDeterminants(); ci++){
00167 double termPsi = globalInput.WF.CI_coeffs(ci) * wd->DcA(ci) * wd->DcB(ci);
00168 psi += termPsi;
00169 WF->getDataForCI(ci,isAlpha,D,ciDet);
00170
00171 double lastRatio = 1.0;
00172 for(int gp=0; gp<grSize; gp++){
00173 ratio = Dc_inv(ci).inverseUpdateOneRow(elecIndex,ciDet,gp);
00174 integrand(gp) += ratio * lastRatio * termPsi;
00175 lastRatio *= ratio;
00176 }
00177 }
00178
00179
00180
00181
00182
00183
00184
00185 double denom;
00186 QMCJastrowElectronElectron jee;
00187 denom = jee.jastrowOnGrid(globalInput.JP,elec,R,grid,integrand);
00188 psi *= denom;
00189 QMCJastrowElectronNuclear jen;
00190 denom = jen.jastrowOnGrid(globalInput.JP,elec,R,grid,integrand);
00191 psi *= denom;
00192 if(globalInput.flags.use_three_body_jastrow == 1){
00193 QMCThreeBodyJastrow jeen;
00194 denom = jeen.jastrowOnGrid(globalInput.JP,elec,R,grid,integrand);
00195 psi *= denom;
00196 }
00197
00198
00199
00200
00201
00202
00203
00204 integral = 0.0;
00205 for(int l=0; l<lmax; l++)
00206 for(int gp=0; gp<grSize; gp++)
00207 integral(l) += integrand(gp) * (MOL->gridLegendre(nuc))(l,gp) * (MOL->gridWeights(nuc))(gp);
00208
00209
00210
00211
00212 double Vnonlocal = 0.0;
00213 for(int l=0; l<lmax; l++)
00214 Vnonlocal += (2.0*l + 1.0) * vnl(l) * integral(l) / psi;
00215
00216 return Vlocal + Vnonlocal;
00217 }
00218
00219 void QMCPotential_Energy::evaluate(Array1D<Array2D<double>*> &R,
00220 Array1D<QMCWalkerData *> &walkerData,
00221 int num)
00222 {
00223 for(int walker = 0; walker < num; walker++)
00224 {
00225 wd = walkerData(walker);
00226
00227 calc_P_en(*R(walker));
00228 calc_P_ee(*R(walker));
00229 Energy_total(walker) = P_nn + P_ee + P_en;
00230
00231 Energy_ne(walker) = P_en;
00232 Energy_ee(walker) = P_ee;
00233 }
00234
00235 wd = 0;
00236 }
00237
00238 void QMCPotential_Energy::calc_P_en(Array2D<double> &R)
00239 {
00240 P_en = 0.0;
00241 double Zeff;
00242
00243 for(int nuc=0; nuc<MOL->Atom_Positions.dim1(); nuc++)
00244 {
00245 if(MOL->usesPsuedo(nuc))
00246 {
00247 for(int el=0; el<R.dim1(); el++)
00248 P_en += evaluatePsuedoPotential(R,el,nuc);
00249 } else {
00250 Zeff = MOL->Zeff(nuc);
00251 for(int el=0; el<R.dim1(); el++)
00252 P_en -= Zeff/wd->riA(el,nuc);
00253 }
00254 }
00255 }
00256
00257 void QMCPotential_Energy::calc_P_nn()
00258 {
00259 P_nn = 0.0;
00260 double r;
00261 double chargei, chargej;
00262
00263
00264
00265 for(int i=0;i<MOL->Atom_Positions.dim1();i++)
00266 {
00267 chargei = MOL->Zeff(i);
00268
00269
00270
00271
00272 for(int j=i+1;j<MOL->Atom_Positions.dim1();j++)
00273 {
00274 chargej = MOL->Zeff(j);
00275 r = MathFunctions::rij(MOL->Atom_Positions,i,j);
00276 P_nn += (chargei*chargej)/r;
00277 }
00278 }
00279 }
00280
00281 void QMCPotential_Energy::calc_P_ee(Array2D<double> &R)
00282 {
00283 P_ee = 0.0;
00284
00285 double chargei, chargej;
00286
00287 if (globalInput.flags.use_hf_potential == 1)
00288 {
00289 for (int i=0; i<R.dim1(); i++)
00290 P_ee += HartreeFock->GetVEff(i, R(i, 0), R(i, 1), R(i, 2));
00291 }
00292 else
00293 {
00294
00295 for (int i=0; i<R.dim1(); i++)
00296 {
00297 chargei = -1.0;
00298 for (int j=0; j<i; j++)
00299 {
00300 chargej = -1.0;
00301 P_ee += (chargei*chargej)/wd->rij(i,j);
00302 }
00303 }
00304 }
00305 }
00306
00307 double QMCPotential_Energy::getEnergy(int which)
00308 {
00309 return Energy_total(which);
00310 }
00311
00312 double QMCPotential_Energy::getEnergyNE(int which)
00313 {
00314 return Energy_ne(which);
00315 }
00316
00317 double QMCPotential_Energy::getEnergyEE(int which)
00318 {
00319 return Energy_ee(which);
00320 }
00321