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