1 /*-------------------------------------------------------------------
2 Copyright 2013 Ravishankar Sundararaman
3 
4 This file is part of JDFTx.
5 
6 JDFTx is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10 
11 JDFTx is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with JDFTx.  If not, see <http://www.gnu.org/licenses/>.
18 -------------------------------------------------------------------*/
19 
20 #include <electronic/SpeciesInfo.h>
21 #include <electronic/SpeciesInfo_internal.h>
22 #include <electronic/Everything.h>
23 #include <electronic/ColumnBundle.h>
24 #include <core/LatticeUtils.h>
25 
26 //------- SpeciesInfo functions related to atomic orbitals -------
27 
28 
29 //Overlap of two radial functions (assumes same grid configuration, but one grid could be shorter)
dot(const RadialFunctionR & X,const RadialFunctionR & Y)30 double dot(const RadialFunctionR& X, const RadialFunctionR& Y)
31 {	size_t nr = std::min(X.f.size(), Y.f.size());
32 	assert(X.r.size() >= nr);
33 	assert(X.dr.size() >= nr);
34 	double ret = 0.;
35 	for(size_t i=0; i<nr; i++)
36 	{	const double& r = X.r[i];
37 		const double& dr = X.dr[i];
38 		ret += (r*r*dr) * (X.f[i] * Y.f[i]);
39 	}
40 	return ret;
41 }
42 //Accumulate radial functions (assumes same grid configuration, but X could be shorter)
axpy(double alpha,const RadialFunctionR & X,RadialFunctionR & Y)43 void axpy(double alpha, const RadialFunctionR& X, RadialFunctionR& Y)
44 {	size_t nr = X.f.size();
45 	assert(Y.f.size() >= nr);
46 	for(size_t i=0; i<nr; i++) Y.f[i] += alpha * X.f[i];
47 }
48 
49 
50 
accumulateAtomicDensity(ScalarFieldTildeArray & nTilde) const51 void SpeciesInfo::accumulateAtomicDensity(ScalarFieldTildeArray& nTilde) const
52 {	//Collect list of distinct magnetizations and corresponding atom positions:
53 	struct MomentDirection //list of atoms with same magnetic moment
54 	{	vector3<> Mhat;
55 		std::vector< vector3<> > atpos;
56 	};
57 	struct MomentMagnitude //list of atoms with same magnetic moment magnitude
58 	{	double Mlength;
59 		std::vector<MomentDirection> Mdirs;
60 	};
61 	std::vector<MomentMagnitude>  Mmags;
62 	if(initialMagneticMoments.size())
63 	{	for(unsigned a=0; a<atpos.size(); a++)
64 		{	const vector3<>& M = initialMagneticMoments[a];
65 			double Mlength = M.length();
66 			vector3<> Mhat = (Mlength ? 1./Mlength : 0.) * M;
67 			bool foundLength = false;
68 			for(MomentMagnitude& Mmag: Mmags) if(fabs(Mlength - Mmag.Mlength) < symmThreshold)
69 			{	bool foundDir = false;
70 				for(MomentDirection& Mdir: Mmag.Mdirs) if((M - Mmag.Mlength*Mdir.Mhat).length_squared() < symmThresholdSq)
71 				{	Mdir.atpos.push_back(atpos[a]);
72 					foundDir = true;
73 					break;
74 				}
75 				if(!foundDir)
76 				{	MomentDirection Mdir;
77 					Mdir.Mhat = Mhat;
78 					Mdir.atpos.push_back(atpos[a]);
79 					Mmag.Mdirs.push_back(Mdir);
80 				}
81 				foundLength = true;
82 				break;
83 			}
84 			if(!foundLength)
85 			{	MomentDirection Mdir;
86 				Mdir.Mhat = Mhat;
87 				Mdir.atpos.push_back(atpos[a]);
88 				MomentMagnitude Mmag;
89 				Mmag.Mlength = Mlength;
90 				Mmag.Mdirs.push_back(Mdir);
91 				Mmags.push_back(Mmag);
92 			}
93 		}
94 	}
95 	else
96 	{	MomentDirection Mdir;
97 		Mdir.atpos = atpos;
98 		MomentMagnitude Mmag;
99 		Mmag.Mlength = 0.;
100 		Mmag.Mdirs.push_back(Mdir);
101 		Mmags.push_back(Mmag);
102 	}
103 	//For each magnetization magnitude:
104 	for(const MomentMagnitude& Mmag: Mmags)
105 	{	if(e->eInfo.nDensities == 1) assert(!Mmag.Mlength);
106 		//Get the radial spin-densities in diagonal basis:
107 		std::vector<RadialFunctionG> nRadial(Mmag.Mlength ? 2 : 1);
108 		for(unsigned s=0; s<nRadial.size(); s++)
109 			getAtom_nRadial(s, Mmag.Mlength, nRadial[s], false);
110 		//Collect contributions for each direction with this magnitude:
111 		for(const MomentDirection& Mdir: Mmag.Mdirs)
112 		{	//Compute structure factor for atoms with current magnetization vector:
113 			ManagedArray<vector3<>> atposCur(Mdir.atpos);
114 			ScalarFieldTilde SG; nullToZero(SG, e->gInfo);
115 			callPref(getSG)(e->gInfo.S, Mdir.atpos.size(), atposCur.dataPref(), 1./e->gInfo.detR, SG->dataPref());
116 			//Spin-densities in diagonal basis
117 			std::vector<ScalarFieldTilde> nDiag;
118 			for(const RadialFunctionG& nRad: nRadial)
119 				nDiag.push_back(nRad * SG);
120 			//Accumulate contributions:
121 			if(nDiag.size()==1)
122 			{	if(nTilde.size()==1)
123 					nTilde[0] += 2.*nDiag[0];
124 				else
125 				{	nTilde[0] += nDiag[0];
126 					nTilde[1] += nDiag[0];
127 				}
128 			}
129 			else
130 			{	nTilde[0] += (0.5*(1.+Mdir.Mhat[2])) * nDiag[0] + (0.5*(1.-Mdir.Mhat[2])) * nDiag[1];
131 				nTilde[1] += (0.5*(1.-Mdir.Mhat[2])) * nDiag[0] + (0.5*(1.+Mdir.Mhat[2])) * nDiag[1];
132 				if(nTilde.size()==4) //noncollinear
133 				{	nTilde[2] += (0.5*Mdir.Mhat[0]) * (nDiag[0] - nDiag[1]); //Re(UpDn) = 0.5*Mx
134 					nTilde[3] += (0.5*Mdir.Mhat[1]) * (nDiag[1] - nDiag[0]); //Im(UpDn) = -0.5*My
135 				}
136 			}
137 		}
138 		for(RadialFunctionG& nRad: nRadial) nRad.free();
139 	}
140 }
141 
accumulateAtomicPotential(ScalarFieldTilde & dTilde) const142 void SpeciesInfo::accumulateAtomicPotential(ScalarFieldTilde& dTilde) const
143 {	//Get radial potential due to one atom:
144 	RadialFunctionG dRadial;
145 	getAtomPotential(dRadial);
146 	//Gets tructure factor:
147 	ScalarFieldTilde SG; nullToZero(SG, e->gInfo);
148 	callPref(getSG)(e->gInfo.S, atpos.size(), atposManaged.dataPref(), 1./e->gInfo.detR, SG->dataPref());
149 	//Accumulate contrbutions:
150 	dTilde += dRadial * SG;
151 	dRadial.free();
152 }
153 
154 //Set atomic orbitals in column bundle from radial functions (almost same operation as setting Vnl)
setAtomicOrbitals(ColumnBundle & Y,bool applyO,int colOffset,const vector3<> * derivDir,const int stressDir) const155 void SpeciesInfo::setAtomicOrbitals(ColumnBundle& Y, bool applyO, int colOffset, const vector3<>* derivDir, const int stressDir) const
156 {	if(!atpos.size()) return;
157 	const auto& fRadial = applyO ? OpsiRadial : psiRadial; //!< select radial function set (psi or Opsi)
158 	int nSpinCopies = 2/e->eInfo.qWeightSum;
159 	int nOrbitalsPerAtom = 0;
160 	for(int l=0; l<int(fRadial.size()); l++)
161 		nOrbitalsPerAtom += nAtomicOrbitals(l)*(2*l+1)*nSpinCopies;
162 	int iCol = colOffset;
163 	for(int l=0; l<int(fRadial.size()); l++)
164 		for(int n=0; n<nAtomicOrbitals(l); n++)
165 		{	setAtomicOrbitals(Y, applyO, n, l, iCol, nOrbitalsPerAtom, derivDir, stressDir);
166 			iCol += (2*l+1)*nSpinCopies;
167 		}
168 }
setAtomicOrbitals(ColumnBundle & psi,bool applyO,unsigned n,int l,int colOffset,int atomColStride,const vector3<> * derivDir,const int stressDir) const169 void SpeciesInfo::setAtomicOrbitals(ColumnBundle& psi, bool applyO, unsigned n, int l, int colOffset, int atomColStride, const vector3<>* derivDir, const int stressDir) const
170 {	if(!atpos.size()) return;
171 	assert(l < int(psiRadial.size()));
172 	assert(int(n) < nAtomicOrbitals(l));
173 	const auto& fRadial = applyO ? OpsiRadial : psiRadial; //!< select radial function set (psi or Opsi)
174 	int nSpinCopies = 2/e->eInfo.qWeightSum;
175 	int nOrbitalsPerAtom = (2*l+1)*nSpinCopies;
176 	if(atomColStride) assert(atomColStride >= nOrbitalsPerAtom); else atomColStride = nOrbitalsPerAtom;
177 	assert(psi.basis); assert(psi.qnum);
178 	assert(colOffset + atomColStride*int(atpos.size()-1) + nOrbitalsPerAtom <= psi.nCols());
179 	if(nSpinCopies>1) assert(psi.isSpinor()); //can have multiple spinor copies only in spinor mode
180 	const Basis& basis = *psi.basis;
181 	if(isRelativistic() && l>0)
182 	{	//find the two orbital indices corresponding to different j of same n
183 		std::vector<int> pArr;
184 		for(int j2=2*l-1; j2<=2*l+1; j2+=2)
185 		{	unsigned ns = 0;
186 			for(unsigned p=0; p<psiRadial[l].size(); p++)
187 				if(psi2j[l][p]==j2)
188 				{	if(ns==n) { pArr.push_back(p); break; }
189 					ns++;
190 				}
191 		}
192 		//Initialize a non-spinor ColumnBundle containing all m's for both j functions:
193 		ColumnBundle V(atpos.size()*nOrbitalsPerAtom, basis.nbasis, &basis, psi.qnum, isGpuEnabled());
194 		int iCol=0;
195 		for(int p: pArr) for(int m=-l; m<=l; m++)
196 		{	size_t atomStride = V.colLength() * nOrbitalsPerAtom;
197 			size_t offs = iCol * V.colLength();
198 			callPref(Vnl)(basis.nbasis, atomStride, atpos.size(), l, m, psi.qnum->k, basis.iGarr.dataPref(),
199 				e->gInfo.G, atposManaged.dataPref(), fRadial[l][p], V.dataPref()+offs, derivDir, stressDir);
200 			iCol++;
201 		}
202 		//Transform the non-spinor ColumnBundle to the spinorial j eigenfunctions:
203 		int N = nOrbitalsPerAtom;
204 		matrix transform = zeroes(2*N, N);
205 		transform.set(0,N,   0,2*l, getYlmToSpinAngleMatrix(l, 2*l-1));
206 		transform.set(N,2*N, 2*l,N, getYlmToSpinAngleMatrix(l, 2*l+1));
207 		for(size_t a=0; a<atpos.size(); a++)
208 			psi.setSub(colOffset+a*atomColStride, V.getSub(a*N,(a+1)*N) * transform);
209 	}
210 	else
211 	{	int iCol = colOffset; //current column
212 		for(int m=-l; m<=l; m++)
213 		{	//Set atomic orbitals for all atoms at specified (n,l,m):
214 			size_t atomStride = psi.colLength() * atomColStride;
215 			size_t offs = iCol * psi.colLength();
216 			callPref(Vnl)(basis.nbasis, atomStride, atpos.size(), l, m, psi.qnum->k, basis.iGarr.dataPref(),
217 				e->gInfo.G, atposManaged.dataPref(), fRadial[l][n], psi.dataPref()+offs, derivDir, stressDir);
218 			if(nSpinCopies>1) //make copy for other spin
219 			{	complex* dataPtr = psi.dataPref()+offs;
220 				for(size_t a=0; a<atpos.size(); a++)
221 				{	callPref(eblas_zero)(2*basis.nbasis, dataPtr+basis.nbasis);
222 					callPref(eblas_copy)(dataPtr+3*basis.nbasis, dataPtr, basis.nbasis);
223 					dataPtr += atomStride;
224 				}
225 			}
226 			iCol += nSpinCopies;
227 		}
228 	}
229 }
nAtomicOrbitals() const230 int SpeciesInfo::nAtomicOrbitals() const
231 {	int nOrbitals = 0;
232 	if(isRelativistic())
233 	{	for(int l=0; l<int(psiRadial.size()); l++)
234 			for(unsigned n=0; n<psiRadial[l].size(); n++)
235 				nOrbitals += (psi2j[l][n]+1);
236 		return nOrbitals * atpos.size();
237 	}
238 	else
239 	{	for(int l=0; l<int(psiRadial.size()); l++)
240 			nOrbitals += (2*l+1)*psiRadial[l].size();
241 		int nSpinCopies = 2/e->eInfo.qWeightSum;
242 		return nOrbitals * atpos.size() * nSpinCopies;
243 	}
244 }
lMaxAtomicOrbitals() const245 int SpeciesInfo::lMaxAtomicOrbitals() const
246 {	return int(psiRadial.size()) - 1;
247 }
nAtomicOrbitals(int l) const248 int SpeciesInfo::nAtomicOrbitals(int l) const
249 {	assert(l >= 0);
250 	if(unsigned(l) >= psiRadial.size()) return -1; //signals end of l
251 	return psiRadial[l].size() / ((isRelativistic() && l>0) ? 2 : 1); //principal quantum number reduced by a factor of 2 when psiRadial counts the j splitting
252 }
atomicOrbitalOffset(unsigned int iAtom,unsigned int n,int l,int m,int s) const253 int SpeciesInfo::atomicOrbitalOffset(unsigned int iAtom, unsigned int n, int l, int m, int s) const
254 {	assert(iAtom < atpos.size());
255 	assert(l >= 0); assert(unsigned(l) < psiRadial.size());
256 	assert(s < e->eInfo.spinorLength());
257 	assert(int(n) < nAtomicOrbitals(l));
258 	int nSpinCopies = 2/e->eInfo.qWeightSum;
259 	int iOrb = 0;
260 	for(int L=0; L<int(psiRadial.size()); L++)
261 	{	int nCount_L = nAtomicOrbitals(L);
262 		iOrb += nCount_L * (2*L+1)*nSpinCopies * iAtom; //orbitals from previous atoms
263 		if(L<=l)
264 			iOrb += (L==l ? n : nCount_L) * (2*L+1)*nSpinCopies; //orbitals from previous l,n at current atom
265 	}
266 	if(isRelativistic())
267 	{	int j2 = 2*l + (s ? -1 : +1); //2*j
268 		int mj2 = 2*m +  + (s ? -1 : +1); //2*m_j
269 		assert(mj2 >= -j2); assert(mj2 <= j2);
270 		if(s==0) iOrb += 2*l; //include orbitals from previous j at current n,l,atom (j = l-1/2 (accessed using s=1) is stored first)
271 		return iOrb + (j2+mj2)/2; //include orbitals from previous m at current j,n,l,atom
272 	}
273 	else
274 	{	assert(m >= -l); assert(m <= l);
275 		return iOrb + (l+m)*nSpinCopies + s; //include orbitals from previous m,s at current n,l,atom
276 	}
277 }
278 
estimateAtomEigs()279 void SpeciesInfo::estimateAtomEigs()
280 {	if(!psiRadial.size()) return; //no orbitals
281 
282 	//Compute eigenvalues if unavailable
283 	if(!atomEigs.size())
284 	{	std::map<int,int> invalidPsis; //some FHI pseudodpotentials store unbound projectors which need to be discarded for LCAO
285 		logPrintf("  Approximate pseudo-atom eigenvalues: ");
286 		atomEigs.resize(psiRadial.size());
287 		double normFac = 1./e->gInfo.detR; //normalization factor in wavefunctions
288 		for(unsigned l=0; l<psiRadial.size(); l++)
289 		{	for(unsigned p=0; p<psiRadial[l].size(); p++)
290 			{	const RadialFunctionR& psi = *(psiRadial[l][p].rFunc);
291 				//Find points deep in the tail of the wavefunction, but still far above roundoff limit:
292 				double r[2], e[2];
293 				double psiThresh[2] = { 3e-7*normFac, 3e-6*normFac };
294 				unsigned i = psi.r.size()-2;
295 				for(int j=0; j<2; j++)
296 				{	for(; i>1; i--) if(fabs(psi.f[i]) > psiThresh[j]) break;
297 					//Apply the Schrodinger operator with V = 0 (tail of a neutral atom)
298 					r[j] = psi.r[i]; double rm = psi.r[i-1], rp = psi.r[i+1];
299 					double Dfp = (psi.f[i+1]/psi.f[i] - 1.) / (rp-r[j]);
300 					double Dfm = (psi.f[i-1]/psi.f[i] - 1.) / (rm-r[j]);
301 					if(Dfp >= 0. || Dfm >= 0.) { e[j] = 0.; continue; } //must be an unbound state
302 					e[j] = (-0.5/(r[j]*r[j])) * (l*(l+1) + (0.5/(rp-rm)) * (Dfp*(rp+r[j])*(rp+r[j]) - Dfm*(rm+r[j])*(rm+r[j])));
303 				}
304 				if(e[0] && e[1])
305 				{	double eCorrected = (r[0]*e[0] - r[1]*e[1]) / (r[0] - r[1]); //correct for remnant Z/r term in non-neutral atoms
306 					atomEigs[l].push_back(eCorrected);
307 				}
308 				else //unbound state
309 				{	atomEigs[l].push_back(std::numeric_limits<double>::infinity()); //make sure it doesn't get occupied
310 					invalidPsis[l]++;
311 				}
312 			}
313 			//Print:
314 			const char orbCode[] = "spdfgh";
315 			if(isRelativistic() && l>0) //split by j
316 			{	int l2 = 2*l;
317 				for(int j2=l2-1; j2<=l2+1; j2+=2)
318 				{	logPrintf("  %c%c (", orbCode[l], (j2<l2 ? '-' : '+'));
319 					for(unsigned p=0; p<psiRadial[l].size(); p++)
320 						if(psi2j[l][p]==j2) logPrintf(" %.2lg", atomEigs[l][p]);
321 					logPrintf(" )");
322 				}
323 			}
324 			else
325 			{	logPrintf("  %c (", orbCode[l]);
326 				for(unsigned p=0; p<psiRadial[l].size(); p++)
327 					logPrintf(" %.2lg", atomEigs[l][p]);
328 				logPrintf(" )");
329 			}
330 		}
331 		logPrintf("\n");
332 		//Report removal of invalid psi's:
333 		for(auto invalidPsi: invalidPsis)
334 			logPrintf("  WARNING: encountered %d l=%d unbound projectors in atomic orbital set.\n", invalidPsi.second, invalidPsi.first);
335 	}
336 }
337 
getAtom_nRadial(int spin,double magneticMoment,RadialFunctionG & nRadial,bool forceNeutral) const338 void SpeciesInfo::getAtom_nRadial(int spin, double magneticMoment, RadialFunctionG& nRadial, bool forceNeutral) const
339 {
340 	int spinCount = (e->eInfo.nDensities==1 ? 1 : 2);
341 	assert(spin >= 0); assert(spin < spinCount);
342 
343 	//Determine occupations:
344 	std::multimap< double, std::pair<unsigned,unsigned> > eigMap; //map from eigenvalues to (l,p)
345 	std::vector<std::vector<double> > atomF(psiRadial.size());
346 	for(unsigned l=0; l<psiRadial.size(); l++)
347 	{	atomF[l].resize(psiRadial[l].size());
348 		for(unsigned p=0; p<psiRadial[l].size(); p++)
349 			eigMap.insert(std::make_pair(atomEigs[l][p], std::make_pair(l,p)));
350 	}
351 	if(spinCount>1 && magneticMoment)
352 		logPrintf("%s (M=%lg) pseudo-atom %s spin occupations: ", name.c_str(), magneticMoment, spin==0 ? "majority" : "minority");
353 	else
354 		logPrintf("%s pseudo-atom occupations: ", name.c_str());
355 	double Nvalence = Z - initialOxidationState;
356 	double N = 0.5*(Nvalence + (1-2*spin)*magneticMoment); //total electrons to fill
357 	if(forceNeutral) N = 0.5*Z; //force neutral unpolarized atom
358 	if(N < 0.)
359 		die("Magnetic moment (%lg) exceeds pseudo-atom valence electron count (%lg) [per spin channel].\n", magneticMoment, Nvalence);
360 	double Favail = N; //electrons yet to be filled
361 	for(auto eigEntry: eigMap) //in ascending order of eigenvalues
362 	{	unsigned l = eigEntry.second.first;
363 		unsigned p = eigEntry.second.second;
364 		double capacity = isRelativistic() ? 0.5*(psi2j[l][p]+1) : (2*l+1);
365 		atomF[l][p] = std::min(Favail, capacity);
366 		Favail -= atomF[l][p];
367 	}
368 	if(Favail > 0.)
369 		die("Insufficient atomic orbitals to occupy %lg electrons (%lg excess electrons) [per spin channel].\n", N, Favail);
370 	double spinFactor = (spinCount>1 && magneticMoment) ? 1. : 2.; //if unpolarized, print total occupations over both spin channels
371 	const char orbCode[] = "spdfgh";
372 	for(unsigned l=0; l<psiRadial.size(); l++) if(psiRadial[l].size())
373 	{	if(isRelativistic() && l>0)
374 		{	int l2 = 2*l;
375 			for(int j2=l2-1; j2<=l2+1; j2+=2)
376 			{	logPrintf("  %c%c (", orbCode[l], (j2<l2 ? '-' : '+'));
377 				for(unsigned p=0; p<psiRadial[l].size(); p++)
378 					if(psi2j[l][p]==j2) logPrintf(" %.2lg", atomF[l][p] * spinFactor);
379 				logPrintf(" )");
380 			}
381 		}
382 		else
383 		{	logPrintf("  %c (", orbCode[l]);
384 			for(unsigned p=0; p<psiRadial[l].size(); p++)
385 				logPrintf(" %.2lg", atomF[l][p] * spinFactor);
386 			logPrintf(" )");
387 		}
388 	}
389 	logPrintf("\n");
390 
391 	//Compute atom electron density: (NOTE: assumes all orbitals are on the same grid)
392 	RadialFunctionR n = *psiRadial[0][0].rFunc; n.f.assign(n.r.size(), 0.); //same grid as orbitals, initialize to 0.
393 	for(unsigned l=0; l<psiRadial.size(); l++)
394 	{	for(unsigned p=0; p<psiRadial[l].size(); p++)
395 		{	const RadialFunctionR& psi = *(psiRadial[l][p].rFunc);
396 			for(unsigned i=0; i<n.r.size(); i++)
397 				n.f[i] += atomF[l][p] * psi.f[i] * psi.f[i];
398 		}
399 		//Augmentation for ultrasofts:
400 		if(Qint.size())
401 		{	for(unsigned p1=0; p1<VnlRadial[l].size(); p1++)
402 				for(unsigned p2=0; p2<=p1; p2++)
403 				{	QijIndex qIndex = { (int)l, (int)p1, (int)l, (int)p2, 0 };
404 					auto Qijl = Qradial.find(qIndex);
405 					if(Qijl==Qradial.end()) continue; //no augmentation for this combination
406 					//Collect density matrix element for this pair of projectors:
407 					double matrixElem = 0.;
408 					for(unsigned o=0; o<psiRadial[l].size(); o++)
409 						matrixElem += atomF[l][o]
410 							* dot(*psiRadial[l][o].rFunc, *VnlRadial[l][p1].rFunc)
411 							* dot(*psiRadial[l][o].rFunc, *VnlRadial[l][p2].rFunc);
412 					//Augment density:
413 					axpy(matrixElem * (p1==p2 ? 1. : 2.), *Qijl->second.rFunc, n);
414 				}
415 		}
416 	}
417 	//Fix normalization:
418 	double normFac = std::pow(e->gInfo.detR,2)/(4.*M_PI);
419 	for(unsigned i=0; i<n.r.size(); i++) n.f[i] *= normFac;
420 	//Transform density:
421 	const double dG = e->gInfo.dGradial;
422 	int nGridLoc = int(ceil(e->gInfo.GmaxGrid/dG))+5;
423 	n.transform(0, dG, nGridLoc, nRadial);
424 }
425 
getAtomPotential(RadialFunctionG & dRadial) const426 void SpeciesInfo::getAtomPotential(RadialFunctionG& dRadial) const
427 {	//Get the radial density of a neutral atom:
428 	RadialFunctionG nRadial;
429 	logSuspend();
430 	getAtom_nRadial(0,0, nRadial, true);
431 	logResume();
432 	RadialFunctionR n = *nRadial.rFunc;
433 	nRadial.free();
434 	//Calculate cumulative charge distribution:
435 	std::vector<double> Qin(n.r.size());
436 	double Qcur = 0.;
437 	for(size_t i=0; i<Qin.size(); i++)
438 	{	double dQ = (2*n.f[i]) * (4*M_PI * n.r[i]*n.r[i] * n.dr[i]); //factor of 2 for spin
439 		Qcur += 0.5*dQ;
440 		Qin[i] = Qcur; //Trapezoidal rule
441 		Qcur += 0.5*dQ;
442 	}
443 	//Calculate electrostatic potential:
444 	RadialFunctionR d = n;
445 	double phiCur = Z/n.r.back();
446 	int iLast = int(Qin.size())-1;
447 	for(int i=iLast; i>=0; i--)
448 	{	double rInv = n.r[i] ? 1./n.r[i] : 0.;
449 		double dphi = Qin[i] * rInv*rInv * n.dr[i];
450 		if(i<iLast)
451 			phiCur += 0.5*dphi;
452 		d.f[i] = phiCur - Z*rInv;
453 		phiCur += 0.5*dphi;
454 	}
455 	//Pseudize potential:
456 	//--- calculate pseudization radius
457 	double Rvdw = 0.;
458 	for(int i=iLast; i>=0; i--)
459 		if(2.*n.f[i] > 0.01)
460 		{	Rvdw = 1.1 * n.r[i]; //DFT+D2 definition for convenience
461 			break;
462 		}
463 	int iVdw = std::upper_bound(n.r.begin(), n.r.end(), Rvdw) - n.r.begin();
464 	assert(iVdw < iLast);
465 	Rvdw = n.r[iVdw]; //round to grid point
466 	//--- pseudize electrostatic potential so that it is zero outside Rvdw
467 	double d0 = d.f[iVdw]; //value
468 	double d1 = (d.f[iVdw+1] - d.f[iVdw-1]) / log(d.r[iVdw+1]/d.r[iVdw-1]); //first derivative w.r.t x = r/Rvdw
469 	double d2 = (d.f[iVdw+1] + d.f[iVdw-1] - 2.*d0) / std::pow(0.5*log(d.r[iVdw+1]/d.r[iVdw-1]),2) - d1; //second derivative w.r.t x = r/Rvdw
470 	double a3 = 10.*d0 - 4.*d1 + 0.5*d2; //expansion x^3 (a3 + a4 x + a5 x^2) that is C2 continuous at 0 and Rvdw
471 	double a4 = -15.*d0 + 7.*d1 - d2;
472 	double a5 = 6.*d0 - 3.*d1 + 0.5*d2;
473 	for(int i=0; i<iVdw; i++)
474 	{	double x = d.r[i] / Rvdw;
475 		d.f[i] -= x*x*x*(a3 + x*(a4 + x*a5));
476 	}
477 	for(size_t i=iVdw; i<d.f.size(); i++)
478 		d.f[i] = 0.;
479 	//Add non-electrostatic part of Vloc:
480 	RadialFunctionR& Vloc = *(VlocRadial.rFunc);
481 	for(size_t i=0; i<d.f.size(); i++)
482 		d.f[i] += Vloc.f[i];
483 	//Transform potential:
484 	const double dG = e->gInfo.dGradial;
485 	int nGridLoc = int(ceil(e->gInfo.GmaxGrid/dG))+5;
486 	d.transform(0, dG, nGridLoc, dRadial);
487 }
488