1 /*-------------------------------------------------------------------
2 Copyright 2011 Ravishankar Sundararaman
3 Copyright 1996-2003 Sohrab Ismail-Beigi
4
5 This file is part of JDFTx.
6
7 JDFTx is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 JDFTx is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with JDFTx. If not, see <http://www.gnu.org/licenses/>.
19 -------------------------------------------------------------------*/
20
21 #include <electronic/IonInfo.h>
22 #include <electronic/Everything.h>
23 #include <electronic/SpeciesInfo.h>
24 #include <electronic/ExCorr.h>
25 #include <electronic/ColumnBundle.h>
26 #include <electronic/VanDerWaals.h>
27 #include <fluid/FluidSolver.h>
28 #include <core/SphericalHarmonics.h>
29 #include <core/Units.h>
30 #include <cstdio>
31 #include <cmath>
32
33 #define MIN_ION_DISTANCE 1e-10
34
IonInfo()35 IonInfo::IonInfo()
36 { shouldPrintForceComponents = false;
37 vdWenable = false;
38 vdWscale = 0.;
39 ljOverride = false;
40 computeStress = false;
41 }
42
setup(const Everything & everything)43 void IonInfo::setup(const Everything &everything)
44 { e = &everything;
45
46 //Force output in same coordinate system as input forces
47 if(forcesOutputCoords==ForcesCoordsPositions)
48 forcesOutputCoords = coordsType==CoordsLattice ? ForcesCoordsLattice : ForcesCoordsCartesian;
49
50 logPrintf("\n---------- Setting up pseudopotentials ----------\n");
51
52 //Choose width of the nuclear gaussian:
53 switch(ionWidthMethod)
54 { case IonWidthManual: break; //manually specified value
55 case IonWidthFFTbox:
56 //set to a multiple of the maximum grid spacing
57 ionWidth = 0.0;
58 for (int i=0; i<3; i++)
59 { double dRi = e->gInfo.h[i].length();
60 ionWidth = std::max(ionWidth, 1.6*dRi);
61 }
62 break;
63 case IonWidthEcut:
64 ionWidth = 0.8*M_PI / sqrt(2*e->cntrl.Ecut);
65 break;
66 }
67 logPrintf("Width of ionic core gaussian charges (only for fluid interactions / plotting) set to %lg\n", ionWidth);
68
69 // Call the species setup routines
70 int nAtomsTot=0;
71 for(auto sp: species)
72 { nAtomsTot += sp->atpos.size();
73 sp->setup(*e);
74 }
75 logPrintf("\nInitialized %d species with %d total atoms.\n", int(species.size()), nAtomsTot);
76 if(!nAtomsTot) logPrintf("Warning: no atoms in the calculation.\n");
77
78 if(not checkPositions())
79 die("\nAtoms are too close, have overlapping pseudopotential cores.\n\n");
80
81 //Determine whether to compute stress with forces:
82 if(e->latticeMinParams.nIterations)
83 computeStress = true; //needed for lattice minimization
84 if(e->ionicDynParams.statMethod != IonicDynamicsParams::StatNone
85 and ( (not (std::isnan)(e->ionicDynParams.P0))
86 or (not (std::isnan)(trace(e->ionicDynParams.stress0))) ) )
87 computeStress = true; //needed for ionic dynamics at constant pressure or stress
88 for(auto dumpPair: e->dump)
89 if(dumpPair.second == DumpStress)
90 computeStress = true; //needed for stress output
91 if(computeStress)
92 { //Check for unsupported features:
93 if(e->coulombParams.Efield.length_squared())
94 die("\nStress calculation not supported with external electric fields.\n\n");
95 //Additional checks in ElecVars for electronic contributions
96 }
97 }
98
printPositions(FILE * fp) const99 void IonInfo::printPositions(FILE* fp) const
100 { fprintf(fp, "# Ionic positions in %s coordinates:\n", coordsType==CoordsLattice ? "lattice" : "cartesian");
101 for(auto sp: species) sp->print(fp);
102 //Optional output of thermostat / barostat velocities:
103 #define WriteStat(stat) \
104 if(stat.size()) \
105 { fprintf(fp, #stat "-velocity"); \
106 stat.print(fp, " %lg"); \
107 }
108 WriteStat(thermostat)
109 WriteStat(barostat)
110 #undef WriteStat
111 fprintf(fp, "\n");
112 }
113
114 // Check for overlapping atoms, returns true if okay
checkPositions() const115 bool IonInfo::checkPositions() const
116 { bool okay = true;
117 double sizetest = 0;
118 vector3<> vtest[2];
119
120 for(auto sp: species)
121 for(unsigned n=0; n < sp->atpos.size(); n++)
122 { if(sp->coreRadius == 0.) continue;
123 vtest[0] = sp->atpos[n];
124 for(auto sp1: species)
125 { if(sp1->coreRadius == 0.) continue;
126 for (unsigned n1 = ((sp1==sp) ? (n+1) : 0); n1 < sp1->atpos.size(); n1++)
127 { vtest[1] = vtest[0] - sp1->atpos[n1];
128 for(int i=0; i<3; i++) // Get periodic distance
129 vtest[1][i] = vtest[1][i] - floor(vtest[1][i] + 0.5);
130 sizetest = sqrt(dot(e->gInfo.R*vtest[1], e->gInfo.R*vtest[1]));
131 if (coreOverlapCondition==additive and (sizetest < (sp->coreRadius + sp1->coreRadius)))
132 { logPrintf("\nWARNING: %s #%d and %s #%d are closer than the sum of their core radii.",
133 sp->name.c_str(), n, sp1->name.c_str(), n1);
134 okay = false;
135 }
136 else if (coreOverlapCondition==vector and (sizetest < sqrt(pow(sp->coreRadius, 2) + pow(sp1->coreRadius, 2))))
137 { logPrintf("\nWARNING: %s #%d and %s #%d are closer than the vector-sum of their core radii.",
138 sp->name.c_str(), n, sp1->name.c_str(), n1);
139 okay = false;
140 }
141 else if(sizetest < MIN_ION_DISTANCE)
142 { die("\nERROR: Ions %s #%d and %s #%d are on top of eachother.\n\n", sp->name.c_str(), n, sp1->name.c_str(), n1);
143 }
144 }
145 }
146 }
147
148 if(not okay) // Add another line after printing core overlap warnings
149 logPrintf("\n");
150
151 return okay;
152 }
153
getZtot() const154 double IonInfo::getZtot() const
155 { double Ztot=0.;
156 for(auto sp: species)
157 Ztot += sp->Z * sp->atpos.size();
158 return Ztot;
159 }
160
update(Energies & ener)161 void IonInfo::update(Energies& ener)
162 { const GridInfo &gInfo = e->gInfo;
163
164 if(ljOverride)
165 { pairPotentialsAndGrad(&ener);
166 return;
167 }
168
169 //----------- update Vlocps, rhoIon, nCore and nChargeball --------------
170 initZero(Vlocps, gInfo);
171 initZero(rhoIon, gInfo);
172 if(nChargeball) nChargeball->zero();
173 ScalarFieldTilde nCoreTilde, tauCoreTilde;
174 for(auto sp: species) //collect contributions to the above from all species
175 sp->updateLocal(Vlocps, rhoIon, nChargeball, nCoreTilde, tauCoreTilde);
176 //Add long-range part to Vlocps and smoothen rhoIon:
177 Vlocps += (*e->coulomb)(rhoIon, Coulomb::PointChargeRight);
178 if(computeStress and ionWidth)
179 rhoIonBare = clone(rhoIon); //remember rhoIon before convolution for stress calculation
180 rhoIon = gaussConvolve(rhoIon, ionWidth);
181 //Process partial core density:
182 if(nCoreTilde) nCore = I(nCoreTilde); // put in real space
183 if(tauCoreTilde) tauCore = I(tauCoreTilde); // put in real space
184
185 //---------- energies dependent on ionic positions alone ----------------
186
187 //Energies due to partial electronic cores:
188 ener.E["Exc_core"] = nCore ? -e->exCorr(nCore, 0, false, &tauCore) : 0.0;
189
190 //Energies from pair-potential terms (Ewald etc.):
191 pairPotentialsAndGrad(&ener);
192
193 //Pulay corrections:
194 ener.E["Epulay"] = calcEpulay();
195 }
196
ionicEnergyAndGrad()197 double IonInfo::ionicEnergyAndGrad()
198 { const ElecInfo &eInfo = e->eInfo;
199 const ElecVars &eVars = e->eVars;
200
201 //Pure LJ pair potential override for ionic algorithm testing:
202 if(ljOverride)
203 { matrix3<> E_RRT;
204 IonicGradient forcesPairPot; forcesPairPot.init(*this);
205 pairPotentialsAndGrad(0, &forcesPairPot, computeStress ? &E_RRT : 0);
206 if(computeStress)
207 { stress = E_RRT * (1./e->gInfo.detR);
208 e->symm.symmetrize(stress);
209 }
210 forces = forcesPairPot;
211 return relevantFreeEnergy(*e);
212 }
213
214 //Initialize lattice gradient for stress if needed:
215 matrix3<> E_RRT; //symmetric matrix derivative E_R . RT
216 if(computeStress)
217 { E_RRT += e->eVars.latticeGrad(); //Electronic contributions
218 calcEpulay(&E_RRT); //Pulay stress
219 }
220
221 //---------- Pair potential terms (Ewald etc.) ---------
222 IonicGradient forcesPairPot; forcesPairPot.init(*this);
223 pairPotentialsAndGrad(0, &forcesPairPot, computeStress ? &E_RRT : 0);
224 e->symm.symmetrize(forcesPairPot);
225 forces = forcesPairPot;
226 if(shouldPrintForceComponents)
227 forcesPairPot.print(*e, globalLog, "forcePairPot");
228
229 //---------- Local part: Vlocps, chargeball, partial core etc.: --------------
230 //compute the complex-conjugate gradient w.r.t the relevant densities/potentials:
231 const ScalarFieldTilde ccgrad_Vlocps = J(eVars.get_nTot()); //just the electron density for Vlocps
232 const ScalarFieldTilde ccgrad_nChargeball = eVars.V_cavity; //cavity potential for chargeballs
233 ScalarFieldTilde ccgrad_rhoIon = (*e->coulomb)(ccgrad_Vlocps, Coulomb::PointChargeLeft); //long-range portion of Vlocps for rhoIon
234 if(eVars.d_fluid) //and electrostatic potential due to fluid (if any):
235 { ccgrad_rhoIon += gaussConvolve(eVars.d_fluid, ionWidth);
236 if(computeStress)
237 { E_RRT -= matrix3<>(1,1,1) * dot(eVars.d_fluid, O(rhoIon)); //cancel volume contribution from rhoIon (which has a 1/detR) from the overall Adiel volume contribution
238 if(ionWidth)
239 E_RRT += 0.5*ionWidth*ionWidth * Lstress(eVars.d_fluid, rhoIon); //stress through gaussConvolve (just a convolution of Lstress)
240 }
241 }
242 ScalarFieldTilde ccgrad_nCore, ccgrad_tauCore;
243 if(nCore) //cavity potential and exchange-correlation coupling to electron density for partial cores:
244 { ScalarField VxcCore, VtauCore;
245 ScalarFieldArray Vxc(eVars.n.size()), Vtau;
246 matrix3<> ExcCore_RRT;
247 double ExcCore = e->exCorr(nCore, &VxcCore, false, &tauCore, &VtauCore, (computeStress ? &ExcCore_RRT : 0));
248 e->exCorr(eVars.get_nXC(), &Vxc, false, &eVars.tau, &Vtau);
249 ScalarField VxcAvg = (Vxc.size()==1) ? Vxc[0] : 0.5*(Vxc[0]+Vxc[1]); //spin-avgd potential
250 ccgrad_nCore = eVars.V_cavity + J(VxcAvg - VxcCore);
251 //Contribution through tauCore (metaGGAs only):
252 if(e->exCorr.needsKEdensity())
253 { ScalarField VtauAvg = (eVars.Vtau.size()==1) ? eVars.Vtau[0] : 0.5*(eVars.Vtau[0]+eVars.Vtau[1]);
254 if(VtauAvg) ccgrad_tauCore += J(VtauAvg - VtauCore);
255 }
256 //Core contribution to stress:
257 if(computeStress)
258 { E_RRT -= ExcCore_RRT;
259 //Additional terms through volume integration factors:
260 double volTerm = ExcCore + dot(ccgrad_nCore, J(nCore))*e->gInfo.detR;
261 if(ccgrad_tauCore) volTerm += dot(ccgrad_tauCore, J(tauCore))*e->gInfo.detR;
262 E_RRT -= matrix3<>(1.,1.,1.) * volTerm;
263 }
264 }
265 //Propagate those gradients to forces:
266 IonicGradient forcesLoc; forcesLoc.init(*this);
267 for(unsigned sp=0; sp<species.size(); sp++)
268 forcesLoc[sp] = species[sp]->getLocalForces(ccgrad_Vlocps, ccgrad_rhoIon,
269 ccgrad_nChargeball, ccgrad_nCore, ccgrad_tauCore);
270 if(e->eVars.fluidSolver) //include extra fluid forces (if any):
271 { IonicGradient fluidForces;
272 e->eVars.fluidSolver->get_Adiel_and_grad(0, 0, &fluidForces);
273 forcesLoc += fluidForces;
274 }
275 e->symm.symmetrize(forcesLoc);
276 forces += forcesLoc;
277 if(shouldPrintForceComponents)
278 forcesLoc.print(*e, globalLog, "forceLoc");
279 //Propagate those gradients to stresses:
280 if(computeStress)
281 { for(const auto& sp: species)
282 E_RRT += sp->getLocalStress(ccgrad_Vlocps, ccgrad_rhoIon,
283 ccgrad_nChargeball, ccgrad_nCore, ccgrad_tauCore);
284 E_RRT += e->coulomb->latticeGradient(ionWidth ? rhoIonBare : rhoIon, ccgrad_Vlocps, Coulomb::PointChargeLeft);
285 }
286
287 //--------- Forces due to nonlocal pseudopotential contributions ---------
288 IonicGradient forcesNL; forcesNL.init(*this);
289 matrix3<> Enl_RRT, *Enl_RRTptr = computeStress ? &Enl_RRT : 0;
290 if(eInfo.hasU) //Include DFT+U contribution if any:
291 rhoAtom_forces(eVars.F, eVars.C, eVars.U_rhoAtom, forcesNL, Enl_RRTptr);
292 augmentDensityGridGrad(eVars.Vscloc, &forcesNL, Enl_RRTptr);
293 for(int q=eInfo.qStart; q<eInfo.qStop; q++)
294 { const QuantumNumber& qnum = e->eInfo.qnums[q];
295 //Collect gradients with respect to VdagCq (not including fillings and state weight):
296 std::vector<matrix> HVdagCq(species.size());
297 EnlAndGrad(qnum, eVars.F[q], eVars.VdagC[q], HVdagCq);
298 augmentDensitySphericalGrad(qnum, eVars.VdagC[q], HVdagCq);
299 //Propagate to atomic positions:
300 for(unsigned sp=0; sp<species.size(); sp++) if(HVdagCq[sp])
301 { matrix grad_CdagOCq = -(eVars.Hsub_eigs[q] * eVars.F[q]); //gradient of energy w.r.t overlap matrix
302 species[sp]->accumNonlocalForces(eVars.C[q], eVars.VdagC[q][sp], HVdagCq[sp]*eVars.F[q], grad_CdagOCq, forcesNL[sp], Enl_RRTptr);
303 }
304 }
305 for(auto& force: forcesNL) //Accumulate contributions over processes
306 mpiWorld->allReduceData(force, MPIUtil::ReduceSum);
307 e->symm.symmetrize(forcesNL);
308 forces += forcesNL;
309 if(shouldPrintForceComponents)
310 forcesNL.print(*e, globalLog, "forceNL");
311 if(computeStress)
312 { mpiWorld->allReduce(Enl_RRT, MPIUtil::ReduceSum);
313 E_RRT += Enl_RRT;
314 }
315
316 //Compute stress tensor from lattice gradient if needed:
317 if(computeStress)
318 { stress = E_RRT * (1./e->gInfo.detR);
319 e->symm.symmetrize(stress);
320 }
321
322 return relevantFreeEnergy(*e);
323 }
324
EnlAndGrad(const QuantumNumber & qnum,const diagMatrix & Fq,const std::vector<matrix> & VdagCq,std::vector<matrix> & HVdagCq) const325 double IonInfo::EnlAndGrad(const QuantumNumber& qnum, const diagMatrix& Fq, const std::vector<matrix>& VdagCq, std::vector<matrix>& HVdagCq) const
326 { double Enlq = 0.0;
327 for(unsigned sp=0; sp<species.size(); sp++)
328 Enlq += species[sp]->EnlAndGrad(qnum, Fq, VdagCq[sp], HVdagCq[sp]);
329 return Enlq;
330 }
331
332
333
augmentOverlap(const ColumnBundle & Cq,ColumnBundle & OCq,std::vector<matrix> * VdagCq) const334 void IonInfo::augmentOverlap(const ColumnBundle& Cq, ColumnBundle& OCq, std::vector<matrix>* VdagCq) const
335 { if(VdagCq) VdagCq->resize(species.size());
336 for(unsigned sp=0; sp<species.size(); sp++)
337 species[sp]->augmentOverlap(Cq, OCq, VdagCq ? &VdagCq->at(sp) : 0);
338 }
339
augmentDensityInit() const340 void IonInfo::augmentDensityInit() const
341 { for(auto sp: species) ((SpeciesInfo&)(*sp)).augmentDensityInit();
342 }
augmentDensitySpherical(const QuantumNumber & qnum,const diagMatrix & Fq,const std::vector<matrix> & VdagCq) const343 void IonInfo::augmentDensitySpherical(const QuantumNumber& qnum, const diagMatrix& Fq, const std::vector<matrix>& VdagCq) const
344 { for(unsigned sp=0; sp<species.size(); sp++)
345 ((SpeciesInfo&)(*species[sp])).augmentDensitySpherical(qnum, Fq, VdagCq[sp]);
346 }
augmentDensityGrid(ScalarFieldArray & n) const347 void IonInfo::augmentDensityGrid(ScalarFieldArray& n) const
348 { for(auto sp: species) sp->augmentDensityGrid(n);
349 }
augmentDensityGridGrad(const ScalarFieldArray & E_n,IonicGradient * forces,matrix3<> * Eaug_RRT) const350 void IonInfo::augmentDensityGridGrad(const ScalarFieldArray& E_n, IonicGradient* forces, matrix3<>* Eaug_RRT) const
351 { for(unsigned sp=0; sp<species.size(); sp++)
352 ((SpeciesInfo&)(*species[sp])).augmentDensityGridGrad(E_n, forces ? &forces->at(sp) : 0, Eaug_RRT);
353 }
augmentDensitySphericalGrad(const QuantumNumber & qnum,const std::vector<matrix> & VdagCq,std::vector<matrix> & HVdagCq) const354 void IonInfo::augmentDensitySphericalGrad(const QuantumNumber& qnum, const std::vector<matrix>& VdagCq, std::vector<matrix>& HVdagCq) const
355 { for(unsigned sp=0; sp<species.size(); sp++)
356 species[sp]->augmentDensitySphericalGrad(qnum, VdagCq[sp], HVdagCq[sp]);
357 }
358
project(const ColumnBundle & Cq,std::vector<matrix> & VdagCq,matrix * rotExisting) const359 void IonInfo::project(const ColumnBundle& Cq, std::vector<matrix>& VdagCq, matrix* rotExisting) const
360 { VdagCq.resize(species.size());
361 for(unsigned sp=0; sp<e->iInfo.species.size(); sp++)
362 { if(rotExisting && VdagCq[sp]) VdagCq[sp] = VdagCq[sp] * (*rotExisting); //rotate and keep the existing projections
363 else
364 { auto V = e->iInfo.species[sp]->getV(Cq);
365 if(V) VdagCq[sp] = (*V) ^ Cq;
366 }
367 }
368 }
369
projectGrad(const std::vector<matrix> & HVdagCq,const ColumnBundle & Cq,ColumnBundle & HCq) const370 void IonInfo::projectGrad(const std::vector<matrix>& HVdagCq, const ColumnBundle& Cq, ColumnBundle& HCq) const
371 { for(unsigned sp=0; sp<species.size(); sp++)
372 if(HVdagCq[sp]) HCq += *(species[sp]->getV(Cq)) * HVdagCq[sp];
373 }
374
375 //----- DFT+U functions --------
376
rhoAtom_nMatrices() const377 size_t IonInfo::rhoAtom_nMatrices() const
378 { size_t nMatrices = 0;
379 for(const auto& sp: species)
380 nMatrices += sp->rhoAtom_nMatrices();
381 return nMatrices;
382 }
383
rhoAtom_initZero(std::vector<matrix> & rhoAtom) const384 void IonInfo::rhoAtom_initZero(std::vector<matrix>& rhoAtom) const
385 { if(!rhoAtom.size()) rhoAtom.resize(rhoAtom_nMatrices());
386 matrix* rhoAtomPtr = rhoAtom.data();
387 for(const auto& sp: species)
388 { sp->rhoAtom_initZero(rhoAtomPtr);
389 rhoAtomPtr += sp->rhoAtom_nMatrices();
390 }
391 }
392
rhoAtom_calc(const std::vector<diagMatrix> & F,const std::vector<ColumnBundle> & C,std::vector<matrix> & rhoAtom) const393 void IonInfo::rhoAtom_calc(const std::vector<diagMatrix>& F, const std::vector<ColumnBundle>& C, std::vector<matrix>& rhoAtom) const
394 { matrix* rhoAtomPtr = rhoAtom.data();
395 for(const auto& sp: species)
396 { sp->rhoAtom_calc(F, C, rhoAtomPtr);
397 rhoAtomPtr += sp->rhoAtom_nMatrices();
398 }
399 }
400
rhoAtom_computeU(const std::vector<matrix> & rhoAtom,std::vector<matrix> & U_rhoAtom) const401 double IonInfo::rhoAtom_computeU(const std::vector<matrix>& rhoAtom, std::vector<matrix>& U_rhoAtom) const
402 { const matrix* rhoAtomPtr = rhoAtom.data();
403 matrix* U_rhoAtomPtr = U_rhoAtom.data();
404 double Utot = 0.;
405 for(const auto& sp: species)
406 { Utot += sp->rhoAtom_computeU(rhoAtomPtr, U_rhoAtomPtr);
407 rhoAtomPtr += sp->rhoAtom_nMatrices();
408 U_rhoAtomPtr += sp->rhoAtom_nMatrices();
409 }
410 return Utot;
411 }
412
rhoAtom_grad(const ColumnBundle & Cq,const std::vector<matrix> & U_rhoAtom,ColumnBundle & HCq) const413 void IonInfo::rhoAtom_grad(const ColumnBundle& Cq, const std::vector<matrix>& U_rhoAtom, ColumnBundle& HCq) const
414 { const matrix* U_rhoAtomPtr = U_rhoAtom.data();
415 for(const auto& sp: species)
416 { sp->rhoAtom_grad(Cq, U_rhoAtomPtr, HCq);
417 U_rhoAtomPtr += sp->rhoAtom_nMatrices();
418 }
419 }
420
rhoAtom_forces(const std::vector<diagMatrix> & F,const std::vector<ColumnBundle> & C,const std::vector<matrix> & U_rhoAtom,IonicGradient & forces,matrix3<> * EU_RRT) const421 void IonInfo::rhoAtom_forces(const std::vector<diagMatrix>& F, const std::vector<ColumnBundle>& C, const std::vector<matrix>& U_rhoAtom, IonicGradient& forces, matrix3<>* EU_RRT) const
422 { const matrix* U_rhoAtomPtr = U_rhoAtom.data();
423 auto forces_sp = forces.begin();
424 for(const auto& sp: species)
425 { sp->rhoAtom_forces(F, C, U_rhoAtomPtr, *forces_sp, EU_RRT);
426 U_rhoAtomPtr += sp->rhoAtom_nMatrices();
427 forces_sp++;
428 }
429 }
430
rHcommutator(const ColumnBundle & Y,int iDir,const matrix & YdagHY) const431 matrix IonInfo::rHcommutator(const ColumnBundle& Y, int iDir, const matrix& YdagHY) const
432 { matrix result = e->gInfo.detR * (Y ^ D(Y, iDir)); //contribution from kinetic term
433 //k-space derivative contributions:
434 vector3<> dirHat; dirHat[iDir] = 1.; //Cartesian unit vector corresponding to iDir
435 complex minus_i(0,-1); //prefactor to k-derivatives
436 //DFT+U corrections:
437 if(e->eInfo.hasU)
438 { const matrix* U_rhoAtomPtr = e->eVars.U_rhoAtom.data();
439 for(const auto& sp: species)
440 { if(sp->rhoAtom_nMatrices())
441 { matrix Urho, psiDagY, ri_psiDagY, ri_psiDagYnew;
442 { ColumnBundle psi;
443 sp->rhoAtom_getV(Y, U_rhoAtomPtr, psi, Urho);
444 psiDagY = psi ^ Y;
445 }
446 { ColumnBundle psiPrime; matrix UrhoUnused;
447 sp->rhoAtom_getV(Y, U_rhoAtomPtr, psiPrime, UrhoUnused, &dirHat);
448 ri_psiDagY = minus_i * (psiPrime ^ Y);
449 }
450 matrix contrib = dagger(ri_psiDagY) * (Urho * psiDagY);
451 result += contrib - dagger(contrib);
452 U_rhoAtomPtr += sp->rhoAtom_nMatrices();
453 }
454 }
455 }
456 //Nonlocal corrections:
457 for(size_t sp=0; sp<species.size(); sp++)
458 if(species[sp]->nProjectors())
459 { const SpeciesInfo& s = *species[sp];
460 const int nAtoms = s.atpos.size();
461 //Get nonlocal psp matrices and projections:
462 matrix Mnl = s.MnlAll;
463 matrix VdagY = (*(s.getV(Y))) ^ Y;
464 matrix ri_VdagY = minus_i * (*(s.getV(Y, &dirHat)) ^ Y);
465 //Ultrasoft augmentation contribution (if any):
466 const matrix id = eye(Mnl.nRows()*nAtoms); //identity
467 matrix Maug = zeroes(id.nRows(), id.nCols());
468 s.augmentDensitySphericalGrad(*Y.qnum, id, Maug);
469 //Apply nonlocal and augmentation corrections to the commutator:
470 matrix contrib = dagger(ri_VdagY) * (tiledBlockMatrix(Mnl, nAtoms)*VdagY + Maug*VdagY);
471 result += contrib - dagger(contrib);
472 //Account for overlap augmentation (if any):
473 if(s.QintAll.nRows())
474 { const matrix& Q = s.QintAll;
475 std::vector<complex> riArr;
476 for(const vector3<>& x: s.atpos)
477 riArr.push_back(dot(e->gInfo.R.row(iDir), x));
478 matrix contrib =
479 ( dagger(VdagY) * (tiledBlockMatrix(Q, nAtoms, &riArr) * VdagY)
480 - dagger(ri_VdagY) * (tiledBlockMatrix(Q, nAtoms) * VdagY) ) * YdagHY;
481 result += contrib - dagger(contrib);
482 }
483 }
484 return result;
485 }
486
nAtomicOrbitals() const487 int IonInfo::nAtomicOrbitals() const
488 { int nAtomic = 0;
489 for(auto sp: species)
490 nAtomic += sp->nAtomicOrbitals();
491 return nAtomic;
492 }
493
getAtomicOrbitals(int q,bool applyO,int extraCols) const494 ColumnBundle IonInfo::getAtomicOrbitals(int q, bool applyO, int extraCols) const
495 { ColumnBundle psi(nAtomicOrbitals()+extraCols, e->basis[q].nbasis * e->eInfo.spinorLength(), &e->basis[q], &e->eInfo.qnums[q], isGpuEnabled());
496 int iCol=0;
497 for(auto sp: species)
498 { sp->setAtomicOrbitals(psi, applyO, iCol);
499 iCol += sp->nAtomicOrbitals();
500 }
501 return psi;
502 }
503
504
pairPotentialsAndGrad(Energies * ener,IonicGradient * forces,matrix3<> * E_RRT) const505 void IonInfo::pairPotentialsAndGrad(Energies* ener, IonicGradient* forces, matrix3<>* E_RRT) const
506 {
507 //Obtain the list of atomic positions and charges:
508 std::vector<Atom> atoms;
509 int Zscale = ljOverride ? 0 : 1;
510 for(size_t spIndex=0; spIndex<species.size(); spIndex++)
511 { const SpeciesInfo& sp = *species[spIndex];
512 for(const vector3<>& pos: sp.atpos)
513 atoms.push_back(Atom(Zscale*sp.Z, pos, vector3<>(0.,0.,0.), sp.atomicNumber, spIndex));
514 }
515 //Compute Ewald sum and gradients (this also moves each Atom::pos into fundamental zone)
516 double Eewald = e->coulomb->energyAndGrad(atoms, E_RRT);
517 //Compute optional pair-potential terms:
518 double EvdW = 0.;
519 if(vdWenable or ljOverride)
520 { double scaleFac = e->vanDerWaals->getScaleFactor(e->exCorr.getName(), vdWscale);
521 EvdW = e->vanDerWaals->energyAndGrad(atoms, scaleFac, E_RRT); //vanDerWaals energy+force
522 }
523 //Store energies and/or forces if requested:
524 if(ener)
525 { ener->E["Eewald"] = Eewald;
526 ener->E["EvdW"] = EvdW;
527 }
528 if(forces)
529 { auto atom = atoms.begin();
530 for(unsigned sp=0; sp<species.size(); sp++)
531 for(unsigned at=0; at<species[sp]->atpos.size(); at++)
532 (*forces)[sp][at] = (atom++)->force;
533 }
534 }
535
calcEpulay(matrix3<> * E_RRT) const536 double IonInfo::calcEpulay(matrix3<>* E_RRT) const
537 { double dEtot_dnG = 0.0; //derivative of Etot w.r.t nG (G-vectors/unit volume)
538 for(auto sp: species)
539 dEtot_dnG += sp->atpos.size() * sp->dE_dnG;
540
541 double nbasisAvg = 0.0;
542 for(int q=e->eInfo.qStart; q<e->eInfo.qStop; q++)
543 nbasisAvg += 0.5*e->eInfo.qnums[q].weight * e->basis[q].nbasis;
544 mpiWorld->allReduce(nbasisAvg, MPIUtil::ReduceSum);
545
546 if(E_RRT)
547 *E_RRT += matrix3<>(1,1,1) * (dEtot_dnG * nbasisAvg/e->gInfo.detR);
548
549 return dEtot_dnG *
550 ( sqrt(2.0)*pow(e->cntrl.Ecut,1.5)/(3.0*M_PI*M_PI) //ideal nG
551 - nbasisAvg/e->gInfo.detR ); //actual nG
552 }
553