Line data Source code
1 : !!****m* ABINIT/m_nucprop
2 : !! NAME
3 : !! m_nucprop
4 : !!
5 : !! FUNCTION
6 : !! routines used to compute properties at the nuclear sites, including
7 : !! electric field gradient and Fermi contact
8 : !!
9 : !! COPYRIGHT
10 : !! Copyright (C) 1998-2026 ABINIT group (MT, JWZ)
11 : !! This file is distributed under the terms of the
12 : !! GNU General Public License, see ~abinit/COPYING
13 : !! or http://www.gnu.org/copyleft/gpl.txt .
14 : !!
15 : !! SOURCE
16 :
17 : #if defined HAVE_CONFIG_H
18 : #include "config.h"
19 : #endif
20 :
21 : #include "abi_common.h"
22 :
23 : module m_nucprop
24 :
25 : use defs_basis
26 : use m_abicore
27 : use m_errors
28 :
29 : use defs_abitypes, only : MPI_type
30 : use m_mpinfo, only : ptabs_fourdp
31 : use m_xmpi, only : xmpi_comm_self, xmpi_sum
32 : use m_geometry, only : xred2xcart
33 : use m_linalg_interfaces, only: dsyev
34 : use m_paw_an, only : paw_an_type
35 : use m_pawang, only : pawang_type
36 : use m_pawrad, only : pawrad_type
37 : use m_pawtab, only : pawtab_type
38 : use m_pawrhoij, only : pawrhoij_type
39 : use m_paw_nmr, only : make_efg_onsite,make_fc_paw
40 : use m_paral_atom, only : get_my_atmtab,free_my_atmtab
41 : use m_special_funcs, only : abi_derfc
42 : use m_matrix, only : matr3inv
43 : use m_symtk, only : matpointsym
44 : use m_fft, only : fourdp
45 :
46 : implicit none
47 :
48 : private
49 : !!***
50 :
51 : public :: calc_efg
52 : public :: calc_fc
53 : public :: make_efg_ion
54 : public :: make_efg_el
55 : !!***
56 :
57 : contains
58 :
59 : !!****f* ABINIT/calc_efg
60 : !! NAME
61 : !! calc_efg
62 : !!
63 : !! FUNCTION
64 : !! calculation and output of electric field gradient tensor at each atomic site
65 : !!
66 : !! INPUTS
67 : !! mpi_atmtab(:)=--optional-- indexes of the atoms treated by current proc
68 : !! comm_atom=--optional-- MPI communicator over atoms
69 : !! mpi_enreg=information about MPI parallelization
70 : !! my_natom=number of atoms treated by current processor
71 : !! natom=number of atoms in cell.
72 : !! nfft=number of points on fft grid
73 : !! ngfft(18)=details of fft
74 : !! nhat(nfft,nspden)=compensation charge density
75 : !! nspden=number of spin densities
76 : !! nsym=number of symmetries in space group
77 : !! ntypat=number of atom types
78 : !! nucefg=1 to print summary output, 2 for detailed output
79 : !! ptcharge(ntypat)=user input charges on atoms to make simple point charge calc
80 : !! paw_an(my_natom) <type(paw_an_type)>=paw arrays given on angular mesh
81 : !! pawang <type(pawang_type)>=paw angular mesh and related data
82 : !! pawrad(ntypat) <type(pawrad_type)>=paw radial mesh and related data
83 : !! pawrhoij(my_natom) <type(pawrhoij_type)>= paw rhoij occupancies and related data
84 : !! pawtab(ntypat) <type(pawtab_type)>=paw tabulated starting data
85 : !! quadmom(ntypat)=quadrupole moments in barns of different atomic nuclei
86 : !! rhor(nfft,nspden)=electron density on grid (strictly $\tilde{n}+\hat{n}$)
87 : !! rprimd(3,3)=matrix relating cartesian coordinates to crystal coordinates
88 : !! symrel(3,3,nsym)=symmetry operators in terms of action on primitive translations
89 : !! tnons(3,nsym)=nonsymmorphic translations
90 : !! typat(natom)=type (integer) for each atom
91 : !! ucvol=unit cell volume in Bohr^3
92 : !! usepaw=1 if we are using PAW formalism, 0 else
93 : !! xred(3,natom)=vectors locating each atom in the unit cell, in crystal coords
94 : !! zion(ntypat)=net core charge on each type of atom
95 : !!
96 : !! OUTPUT
97 : !! (only writing, printing)
98 : !!
99 : !! SOURCE
100 :
101 18 : subroutine calc_efg(efg,mpi_enreg,my_natom,natom,nfft,ngfft,nhat,nspden,nsym,nucefg,ntypat,&
102 9 : paw_an,pawang,pawrad,pawrhoij,pawtab,&
103 9 : ptcharge,quadmom,rhor,rprimd,symrel,tnons,typat,ucvol,usepaw,xred,zion,&
104 9 : mpi_atmtab,comm_atom) ! optional arguments (parallelism)
105 :
106 : !Arguments ------------------------------------
107 : !scalars
108 : integer,intent(in) :: my_natom,natom,nfft,nspden,nsym,nucefg,ntypat,usepaw
109 : integer,optional,intent(in) :: comm_atom
110 : real(dp),intent(in) :: ucvol
111 : type(MPI_type),intent(in) :: mpi_enreg
112 : type(pawang_type),intent(in) :: pawang
113 : !arrays
114 : integer,intent(in) :: ngfft(18),symrel(3,3,nsym),typat(natom)
115 : integer,optional,target,intent(in) :: mpi_atmtab(:)
116 : real(dp),intent(in) :: nhat(nfft,nspden),ptcharge(ntypat)
117 : real(dp),intent(in) :: quadmom(ntypat),rhor(nfft,nspden),rprimd(3,3)
118 : real(dp),intent(in) :: tnons(3,nsym),zion(ntypat)
119 : real(dp),intent(inout) :: xred(3,natom)
120 : real(dp),intent(out) :: efg(3,3,natom)
121 : type(paw_an_type),intent(in) :: paw_an(my_natom)
122 : type(pawrad_type),intent(in) :: pawrad(ntypat)
123 : type(pawrhoij_type),intent(in) :: pawrhoij(my_natom)
124 : type(pawtab_type),intent(in) :: pawtab(ntypat)
125 :
126 : !Local variables-------------------------------
127 : !scalars
128 : integer :: ii,INFO,LDA,LWORK,N,iatom,my_comm_atom
129 : logical :: my_atmtab_allocated,paral_atom
130 : real(dp) :: cq,efgsi21,eta,vxx,vyy,vzz
131 : character(len=500) :: message
132 : !arrays
133 9 : integer,pointer :: my_atmtab(:)
134 : real(dp) :: eigval(3),matr(3,3),work(8)
135 9 : real(dp),allocatable :: efg_el(:,:,:),efg_ion(:,:,:),efg_paw(:,:,:)
136 9 : real(dp),allocatable :: efg_point_charge(:,:,:)
137 :
138 : ! ************************************************************************
139 :
140 : !Compatibility tests
141 9 : if (usepaw /= 1) then
142 0 : message = ' usepaw /= 1 but EFG calculation requires PAW '
143 0 : ABI_ERROR(message)
144 : end if
145 :
146 9 : efgsi21=efg_si*1.0E-21 ! efg_si is electric field gradient in SI units, defined in
147 : ! defs_basis. Multiply by 10E-21 for nice printing below.
148 : ! 1 EFG in au is 9.725E21 volts/m^2
149 :
150 : !Set up parallelism over atoms
151 9 : paral_atom=(present(comm_atom).and.(my_natom/=natom))
152 9 : nullify(my_atmtab);if (present(mpi_atmtab)) my_atmtab => mpi_atmtab
153 9 : my_comm_atom=xmpi_comm_self;if (present(comm_atom)) my_comm_atom=comm_atom
154 9 : call get_my_atmtab(my_comm_atom,my_atmtab,my_atmtab_allocated,paral_atom,natom,my_natom_ref=my_natom)
155 :
156 27 : ABI_MALLOC(efg_el,(3,3,natom))
157 18 : ABI_MALLOC(efg_ion,(3,3,natom))
158 18 : ABI_MALLOC(efg_paw,(3,3,natom))
159 18 : ABI_MALLOC(efg_point_charge,(3,3,natom))
160 542 : efg_el(:,:,:) = zero
161 542 : efg_ion(:,:,:) = zero
162 542 : efg_paw(:,:,:) = zero
163 542 : efg_point_charge(:,:,:) = zero
164 :
165 9 : call make_efg_el(efg_el,mpi_enreg,natom,nfft,ngfft,nhat,nspden,nsym,rhor,rprimd,symrel,tnons,xred)
166 :
167 9 : call make_efg_ion(efg_ion,natom,nsym,ntypat,rprimd,symrel,tnons,typat,ucvol,xred,zion)
168 :
169 9 : if (paral_atom) then
170 : call make_efg_onsite(efg_paw,my_natom,natom,nsym,ntypat,paw_an,pawang,pawrhoij,pawrad,pawtab,&
171 0 : & rprimd,symrel,tnons,xred,comm_atom=my_comm_atom,mpi_atmtab=my_atmtab)
172 : else
173 : call make_efg_onsite(efg_paw,my_natom,natom,nsym,ntypat,paw_an,pawang,pawrhoij,pawrad,pawtab,&
174 9 : & rprimd,symrel,tnons,xred)
175 : end if
176 :
177 : !calculate efg due to pure point charges, as input in variable ptcharge(ntypat)
178 : !note here all atoms of the same type will have the same valence; in the future this
179 : !could be made more flexible by having ptcharge(natom) but that will require a slightly
180 : !different version than the existing make_efg_ion routine
181 9 : if(nucefg > 2) then
182 1 : call make_efg_ion(efg_point_charge,natom,nsym,ntypat,rprimd,symrel,tnons,typat,ucvol,xred,ptcharge)
183 : end if
184 :
185 542 : efg(:,:,:) = efg_el(:,:,:) + efg_ion(:,:,:) + efg_paw(:,:,:)
186 :
187 9 : write(message,'(a,a,a)' ) ch10,' Electric Field Gradient Calculation ',ch10
188 9 : call wrtout(ab_out,message,'COLL')
189 :
190 9 : LDA=3; LWORK=8;N=3 ! these parameters are needed for the LAPACK dsyev routine
191 50 : do iatom = 1, natom
192 533 : matr(:,:) = efg(:,:,iatom)
193 41 : call dsyev('V','U',N,matr,LDA,eigval,work,LWORK,INFO) ! get eigenvalues and eigenvectors
194 41 : if (eigval(3) > abs(eigval(1)) ) then ! In NMR, the convention is that whatever component is
195 : ! largest in magnitude is called Vzz, next comes Vxx, then Vyy
196 16 : vzz = eigval(3)
197 16 : vxx = eigval(1)
198 16 : vyy = eigval(2)
199 : else
200 25 : vzz = eigval(1)
201 25 : vxx = eigval(3)
202 25 : vyy = eigval(2)
203 : end if
204 : ! Cq = vzz*(eQ)/h, where Q is the nuclear quad moment in barns (10E-28 m2)
205 : ! Multiply Q by 1E-8 * Ang_Bohr**2 to get nuclear moment in Bohr^2
206 : ! resulting vzz*(eQ) is energy in Ha (recall e = 1 in au)
207 : ! then convert to MHz with Ha_THz*1.E6
208 : ! resulting factors are Ang_Bohr**2*Ha_THz*1.0D-2
209 41 : cq = vzz*quadmom(typat(iatom))*Ang_Bohr**2*Ha_THz*1.0D-2
210 41 : if (abs(cq) > tol8) then
211 29 : eta = abs(vxx-vyy)/abs(vzz)
212 : else
213 12 : cq = zero
214 12 : eta = zero ! if Cq is small then eta is meaningless
215 : end if
216 :
217 41 : write(message,'(a,a,i4,a,i4)')ch10,' atom : ',iatom,' typat : ',typat(iatom)
218 41 : call wrtout(ab_out,message,'COLL')
219 41 : if (nucefg > 1) then
220 41 : write(message,'(2a,f9.4,a,f9.4,a,f9.4)') ch10,' Nuclear quad. mom. (barns) : ',quadmom(typat(iatom)),&
221 82 : & ' Cq (MHz) : ',cq,' eta : ',eta
222 41 : call wrtout(ab_out,message,'COLL')
223 : end if
224 :
225 : ! for printing and test portability, it's better to simply set very small eigvals to zero
226 164 : do ii=1,3
227 164 : if (abs(eigval(ii))<tol8) eigval(ii)=zero
228 : end do
229 41 : write(message,'(2a,f13.6,a,f16.8,a,a,3f13.6)')ch10,' efg eigval (au) : ',eigval(1),' ; (1.0E+21 V/m^2) : ',eigval(1)*efgsi21,ch10,&
230 82 : & '- eigvec : ',matr(1,1),matr(2,1),matr(3,1)
231 41 : call wrtout(ab_out,message,'COLL')
232 41 : write(message,'(2a,f13.6,a,f16.8,a,a,3f13.6)')ch10,' efg eigval (au) : ',eigval(2),' ; (1.0E+21 V/m^2) : ',eigval(2)*efgsi21,ch10,&
233 82 : & '- eigvec : ',matr(1,2),matr(2,2),matr(3,2)
234 41 : call wrtout(ab_out,message,'COLL')
235 41 : write(message,'(2a,f13.6,a,f16.8,a,a,3f13.6)')ch10,' efg eigval (au) : ',eigval(3),' ; (1.0E+21 V/m^2) : ',eigval(3)*efgsi21,ch10,&
236 82 : & '- eigvec : ',matr(1,3),matr(2,3),matr(3,3)
237 41 : call wrtout(ab_out,message,'COLL')
238 41 : write(message,'(a,a,3f13.6)')ch10,' total efg : ',efg(1,1,iatom),efg(1,2,iatom),efg(1,3,iatom)
239 41 : call wrtout(ab_out,message,'COLL')
240 41 : write(message,'(a,3f13.6)')' total efg : ',efg(2,1,iatom),efg(2,2,iatom),efg(2,3,iatom)
241 41 : call wrtout(ab_out,message,'COLL')
242 41 : write(message,'(a,3f13.6,a)')' total efg : ',efg(3,1,iatom),efg(3,2,iatom),efg(3,3,iatom),ch10
243 41 : call wrtout(ab_out,message,'COLL')
244 41 : write(message,'(a,a,3f13.6)')ch10,' efg_el : ',efg_el(1,1,iatom),efg_el(1,2,iatom),efg_el(1,3,iatom)
245 41 : call wrtout(ab_out,message,'COLL')
246 41 : write(message,'(a,3f13.6)')' efg_el : ',efg_el(2,1,iatom),efg_el(2,2,iatom),efg_el(2,3,iatom)
247 41 : call wrtout(ab_out,message,'COLL')
248 41 : write(message,'(a,3f13.6,a)')' efg_el : ',efg_el(3,1,iatom),efg_el(3,2,iatom),efg_el(3,3,iatom),ch10
249 41 : call wrtout(ab_out,message,'COLL')
250 41 : write(message,'(a,3f13.6)')' efg_ion : ',efg_ion(1,1,iatom),efg_ion(1,2,iatom),efg_ion(1,3,iatom)
251 41 : call wrtout(ab_out,message,'COLL')
252 41 : write(message,'(a,3f13.6)')' efg_ion : ',efg_ion(2,1,iatom),efg_ion(2,2,iatom),efg_ion(2,3,iatom)
253 41 : call wrtout(ab_out,message,'COLL')
254 41 : write(message,'(a,3f13.6,a)')' efg_ion : ',efg_ion(3,1,iatom),efg_ion(3,2,iatom),efg_ion(3,3,iatom),ch10
255 41 : call wrtout(ab_out,message,'COLL')
256 41 : write(message,'(a,3f13.6)')' efg_paw : ',efg_paw(1,1,iatom),efg_paw(1,2,iatom),efg_paw(1,3,iatom)
257 41 : call wrtout(ab_out,message,'COLL')
258 41 : write(message,'(a,3f13.6)')' efg_paw : ',efg_paw(2,1,iatom),efg_paw(2,2,iatom),efg_paw(2,3,iatom)
259 41 : call wrtout(ab_out,message,'COLL')
260 41 : write(message,'(a,3f13.6,a)')' efg_paw : ',efg_paw(3,1,iatom),efg_paw(3,2,iatom),efg_paw(3,3,iatom),ch10
261 41 : call wrtout(ab_out,message,'COLL')
262 50 : if (nucefg > 2) then ! write output of pure pointcharge calculation
263 78 : matr(:,:) = efg_point_charge(:,:,iatom)
264 6 : call dsyev('V','U',N,matr,LDA,eigval,work,LWORK,INFO) ! get eigenvalues and eigenvectors
265 6 : if (eigval(3) > abs(eigval(1)) ) then ! In NMR, the convention is that whatever component is
266 : ! largest in magnitude is called Vzz, next comes Vxx, then Vyy
267 0 : vzz = eigval(3)
268 0 : vxx = eigval(1)
269 0 : vyy = eigval(2)
270 : else
271 6 : vzz = eigval(1)
272 6 : vxx = eigval(3)
273 6 : vyy = eigval(2)
274 : end if
275 6 : cq = vzz*quadmom(typat(iatom))*Ang_Bohr**2*Ha_THz*1.0D-2
276 6 : if (abs(cq) > tol8) then
277 4 : eta = abs(vxx-vyy)/abs(vzz)
278 : else
279 2 : eta = zero ! if Cq is small then eta is meaningless
280 : end if
281 6 : write(message,'(a,f9.4,a,f9.4)') ' Point charge Cq = ',cq,' MHz eta = ',eta
282 6 : call wrtout(ab_out,message,'COLL')
283 6 : write(message,'(2a,f13.6,a,f16.8,a,a,3f13.6)')ch10,' point charge eigval (au) : ',&
284 6 : & eigval(1),' ; (1.0E+21 V/m^2) : ',eigval(1)*efgsi21,ch10,&
285 12 : & '- eigvec : ',matr(1,1),matr(2,1),matr(3,1)
286 6 : call wrtout(ab_out,message,'COLL')
287 6 : write(message,'(2a,f13.6,a,f16.8,a,a,3f13.6)')ch10,' point charge eigval (au) : ',&
288 6 : & eigval(2),' ; (1.0E+21 V/m^2) : ',eigval(2)*efgsi21,ch10,&
289 12 : & '- eigvec : ',matr(1,2),matr(2,2),matr(3,2)
290 6 : call wrtout(ab_out,message,'COLL')
291 6 : write(message,'(2a,f13.6,a,f16.8,a,a,3f13.6)')ch10,' point charge eigval (au) : ',&
292 6 : & eigval(3),' ; (1.0E+21 V/m^2) : ',eigval(3)*efgsi21,ch10,&
293 12 : & '- eigvec : ',matr(1,3),matr(2,3),matr(3,3)
294 6 : call wrtout(ab_out,message,'COLL')
295 6 : write(message,'(a,a,3f13.6)')ch10,' point charge efg : ',efg_point_charge(1,1,iatom),&
296 12 : & efg_point_charge(1,2,iatom),efg_point_charge(1,3,iatom)
297 6 : call wrtout(ab_out,message,'COLL')
298 6 : write(message,'(a,3f13.6)')' point charge efg : ',efg_point_charge(2,1,iatom),&
299 12 : & efg_point_charge(2,2,iatom),efg_point_charge(2,3,iatom)
300 6 : call wrtout(ab_out,message,'COLL')
301 6 : write(message,'(a,3f13.6,a)')' point charge efg : ',efg_point_charge(3,1,iatom),&
302 12 : & efg_point_charge(3,2,iatom),efg_point_charge(3,3,iatom),ch10
303 6 : call wrtout(ab_out,message,'COLL')
304 : end if
305 : end do
306 9 : write(message,'(3a)')ch10,ch10,ch10
307 9 : call wrtout(ab_out,message,'COLL')
308 :
309 9 : ABI_FREE(efg_el)
310 9 : ABI_FREE(efg_ion)
311 9 : ABI_FREE(efg_paw)
312 9 : ABI_FREE(efg_point_charge)
313 :
314 : !Destroy atom table used for parallelism
315 9 : call free_my_atmtab(my_atmtab,my_atmtab_allocated)
316 :
317 : !DEBUG
318 : !write(std_out,*)' calc_efg : exit '
319 : !stop
320 : !ENDDEBUG
321 :
322 9 : end subroutine calc_efg
323 : !!***
324 :
325 : !!***
326 : !!****f* ABINIT/calc_fc
327 : !! NAME
328 : !! calc_fc
329 : !!
330 : !! FUNCTION
331 : !! calculation and output of Fermi-contact term at each atomic site
332 : !!
333 : !! INPUTS
334 : !! mpi_atmtab(:)=--optional-- indexes of the atoms treated by current proc
335 : !! comm_atom=--optional-- MPI communicator over atoms
336 : !! my_natom=number of atoms treated by current processor
337 : !! natom=number of atoms in cell.
338 : !! nspden=number of spin density components
339 : !! ntypat=number of atom types
340 : !! pawrad(ntypat) <type(pawrad_type)>=paw radial mesh and related data
341 : !! pawrhoij(natom) <type(pawrhoij_type)>= paw rhoij occupancies and related data
342 : !! pawtab(ntypat) <type(pawtab_type)>=paw tabulated starting data
343 : !! typat(natom)=type (integer) for each atom
344 : !! usepaw=1 if PAW is activated
345 : !!
346 : !! OUTPUT
347 : !! (only writing, printing)
348 : !!
349 : !! SIDE EFFECTS
350 : !!
351 : !!
352 : !! NOTES
353 : !!
354 : !! SOURCE
355 :
356 10 : subroutine calc_fc(my_natom,natom,nspden,ntypat,pawrad,pawrhoij,pawtab,typat,usepaw,&
357 5 : & mpi_atmtab,comm_atom) ! optional arguments (parallelism)
358 :
359 : !Arguments ------------------------------------
360 : !scalars
361 : integer,intent(in) :: my_natom,natom,nspden,ntypat,usepaw
362 : integer,optional,intent(in) :: comm_atom
363 : !arrays
364 : integer,intent(in) :: typat(natom)
365 : integer,optional,target,intent(in) :: mpi_atmtab(:)
366 : type(pawrad_type),intent(in) :: pawrad(ntypat)
367 : type(pawrhoij_type),intent(in) :: pawrhoij(my_natom)
368 : type(pawtab_type),intent(in) :: pawtab(ntypat)
369 :
370 : !Local variables-------------------------------
371 : !scalars
372 : integer :: iatom,my_comm_atom
373 : logical :: my_atmtab_allocated,paral_atom
374 : character(len=500) :: message
375 : !arrays
376 5 : integer,pointer :: my_atmtab(:)
377 5 : real(dp),allocatable :: fc(:,:)
378 :
379 : !***********************************************************************
380 :
381 : !Compatibility tests
382 5 : if (usepaw /= 1) then
383 0 : message = ' usepaw /= 1 but Fermi-contact calculation requires PAW '
384 0 : ABI_ERROR(message)
385 : end if
386 :
387 : !Set up parallelism over atoms
388 5 : paral_atom=(present(comm_atom).and.(my_natom/=natom))
389 5 : nullify(my_atmtab);if (present(mpi_atmtab)) my_atmtab => mpi_atmtab
390 5 : my_comm_atom=xmpi_comm_self;if (present(comm_atom)) my_comm_atom=comm_atom
391 5 : call get_my_atmtab(my_comm_atom,my_atmtab,my_atmtab_allocated,paral_atom,natom,my_natom_ref=my_natom)
392 :
393 : !Initialization
394 20 : ABI_MALLOC(fc,(nspden,natom))
395 :
396 : !Computation
397 5 : if (paral_atom) then
398 : call make_fc_paw(fc,my_natom,natom,nspden,ntypat,pawrhoij,pawrad,pawtab,&
399 0 : & comm_atom=my_comm_atom,mpi_atmtab=my_atmtab)
400 : else
401 5 : call make_fc_paw(fc,my_natom,natom,nspden,ntypat,pawrhoij,pawrad,pawtab)
402 : end if
403 :
404 : !Printing
405 5 : write(message,'(a,a,a)' ) ch10,' Fermi-contact Term Calculation ',ch10
406 5 : call wrtout(ab_out,message,'COLL')
407 :
408 26 : do iatom = 1, natom
409 26 : if (nspden == 2) then
410 1 : write(message,'(a,i3,a,i3,a,f12.4)') ' Atom ',iatom,', typat ',typat(iatom),': FC total = ',&
411 2 : & fc(1,iatom)+fc(2,iatom)
412 1 : call wrtout(ab_out,message,'COLL')
413 1 : write(message,'(a,i3,a,i3,a,f12.4)') ' Atom ',iatom,', typat ',typat(iatom),': FC up - down = ',&
414 2 : & fc(1,iatom)-fc(2,iatom)
415 1 : call wrtout(ab_out,message,'COLL')
416 : else
417 20 : write(message,'(a,i3,a,i3,a,f12.4)') ' Atom ',iatom,', typat ',typat(iatom),': FC = ',&
418 40 : & fc(1,iatom)
419 20 : call wrtout(ab_out,message,'COLL')
420 : end if
421 : end do
422 :
423 5 : write(message,'(3a)')ch10,ch10,ch10
424 5 : call wrtout(ab_out,message,'COLL')
425 :
426 : !Memory deallocation
427 5 : ABI_FREE(fc)
428 :
429 : !Destroy atom table used for parallelism
430 5 : call free_my_atmtab(my_atmtab,my_atmtab_allocated)
431 :
432 5 : end subroutine calc_fc
433 : !!***
434 :
435 : !!****f* ABINIT/make_efg_ion
436 : !! NAME
437 : !! make_efg_ion
438 : !!
439 : !! FUNCTION
440 : !! compute the electric field gradient due to ionic cores
441 : !!
442 : !! INPUTS
443 : !! natom, number of atoms in the unit cell
444 : !! nsym=number of symmetries in space group
445 : !! ntypat, the number of types of atoms in the unit cell
446 : !! rprimd(3,3), the matrix giving the transformation from crystal to cartesian coordinates
447 : !! symrel(3,3,nsym)=symmetry operators in terms of action on primitive translations
448 : !! tnons(3,nsym) = nonsymmorphic translations
449 : !! typat(natom), the type of each atom in the unit cell
450 : !! ucvol, the volume of the unit cell in atomic units
451 : !! xred(3,natom) the location of each atom in the cell in crystallographic coordinates
452 : !! zion(ntypat) the net charge on each type of atom
453 : !!
454 : !! OUTPUT
455 : !! efg(3,3,natom), the 3x3 efg tensors at each atomic site
456 : !!
457 : !! SIDE EFFECTS
458 : !!
459 : !! NOTES
460 : !! This routine computes the electric field gradient, specifically the components
461 : !! $\partial^2 V/\partial x_\alpha \partial x_\beta$ of the potential generated by the ionic cores,
462 : !! at each atomic site in the unit cell.
463 : !! Key references:
464 : !! Profeta, Mauri, and Pickard, ``Accurate first principles prediction of $^{17}$O NMR parameters in
465 : !! SiO$_2$: Assignment of the zeolite ferrierite spectrum'', J. Am. Chem. Soc. 125, 541--548 (2003) [[cite:Profeta2003]];
466 : !! A. Honma, ``Dipolar lattice-sums with applications to the exciton bands of anthracene crystal and
467 : !! the crystal field due to point charges'', J. Phys. Soc. Jpn. 42, 1129--1135 (1977) [[cite:Honma1977]];
468 : !! and Kresse and Joubert, ``From ultrasoft pseudopotentials to the projector augmented wave method'',
469 : !! Phys. Rev. B. 59, 1758--1775 (1999) [[cite:Kresse1999]]. In Kresse and Joubert's notation, the ionic cores are $n_{Zc}$;
470 : !! these charges are given by the net core charges on the pseudoatoms. Due to otherwise slow convergence,
471 : !! the sum over atoms is carried out by an Ewald method as detailed in the Honma reference, specifically
472 : !! his Eq. 4.8.
473 : !!
474 : !! SOURCE
475 :
476 10 : subroutine make_efg_ion(efg,natom,nsym,ntypat,rprimd,symrel,tnons,typat,ucvol,xred,zion)
477 :
478 : !Arguments ------------------------------------
479 : !scalars
480 : integer,intent(in) :: natom,nsym,ntypat
481 : real(dp) :: ucvol
482 : !arrays
483 : integer,intent(in) :: symrel(3,3,nsym),typat(natom)
484 : real(dp),intent(in) :: rprimd(3,3),tnons(3,nsym)
485 : real(dp),intent(in) :: zion(ntypat)
486 : real(dp),intent(inout) :: xred(3,natom)
487 : real(dp),intent(out) :: efg(3,3,natom)
488 : !Local variables-------------------------------
489 : !scalars
490 : integer :: iatom,ishell,ii,jatom,jj,nshell,sx,sy,sz
491 : real(dp) :: cph,dampfac,derfc_karg,derivs,gsq,karg
492 : real(dp) :: lenrho,phase,qk,rlkcut,trace,xi0
493 : real(dp) :: glkcut
494 : !arrays
495 : real(dp) :: cvec(3),gvec(3),gpl(3),gprimd(3,3)
496 : real(dp) :: rhok(3),rhored(3),rpl(3)
497 10 : real(dp),allocatable :: efg_g(:,:,:),efg_r(:,:,:)
498 10 : real(dp),allocatable :: xcart(:,:)
499 :
500 : ! ************************************************************************
501 :
502 : !DEBUG
503 : !write(std_out,*)' make_efg_ion : enter'
504 : !ENDDEBUG
505 :
506 30 : ABI_MALLOC(efg_g,(3,3,natom))
507 20 : ABI_MALLOC(efg_r,(3,3,natom))
508 30 : ABI_MALLOC(xcart,(3,natom))
509 621 : efg(:,:,:) = zero ! final efg tensor
510 621 : efg_g(:,:,:) = zero ! part of tensor accumulated in G space
511 621 : efg_r(:,:,:) = zero ! part of tensor accumulated in R space
512 :
513 10 : call xred2xcart(natom,rprimd,xcart,xred) ! get atomic locations in cartesian coords
514 :
515 40 : do ii = 1, 3 ! generate the lengths of the unit cell edges in atomic units
516 40 : rpl(ii) = sqrt(rprimd(1,ii)**2+rprimd(2,ii)**2+rprimd(3,ii)**2)
517 : end do
518 90 : xi0 = sqrt(pi/(maxval(rpl)*minval(rpl))) ! this estimate for xi0 is from Honma's paper
519 :
520 10 : call matr3inv(rprimd,gprimd) ! gprimd holds the inverse transpose of rprimd
521 : !remember ordering: rprimd( (x_comp,y_comp,z_comp), (edge 1, edge 2, edge 3) )
522 : !while gprimd( (edge 1, edge 2, edge 3),(x_comp, y_comp, z_comp) )
523 40 : do ii = 1, 3 ! generate the lengths of the reciprocal cell edges
524 40 : gpl(ii) = sqrt(gprimd(ii,1)**2+gprimd(ii,2)**2+gprimd(ii,3)**2)
525 : end do
526 :
527 : !go out enough shells such that g**2/4*xi0**2 is of order 30
528 50 : nshell = int(anint(sqrt(30.0)*xi0/(pi*minval(gpl))))
529 50 : glkcut = (0.95*nshell*two*pi*minval(gpl))**2
530 :
531 56 : do ishell = 0, nshell ! loop over shells
532 270 : do sx = -ishell, ishell
533 1586 : do sy = -ishell, ishell
534 10874 : do sz = -ishell, ishell
535 10660 : if ( .not. (sx==0 .and. sy==0 .and. sz==0) ) then ! avoid origin
536 : ! constrain to be on shell surface, not interior
537 9288 : if ( abs(sx)==ishell .or. abs(sy)==ishell .or. abs(sz)==ishell ) then
538 5736 : cvec(1)=sx;cvec(2)=sy;cvec(3)=sz
539 : ! make the g vector in cartesian coords
540 5736 : gvec(:) = zero
541 22944 : do ii = 1, 3
542 74568 : do jj = 1, 3
543 68832 : gvec(ii) = gvec(ii) + gprimd(ii,jj)*cvec(jj)*two*pi
544 : end do
545 : end do
546 22944 : gsq = dot_product(gvec,gvec)
547 5736 : if(gsq < glkcut) then
548 1200 : dampfac = exp(-gsq/(4.0*xi0*xi0)) ! see Honma eq. 4.8
549 7364 : do iatom = 1, natom
550 42576 : do jatom = 1, natom
551 35212 : qk = zion(typat(jatom)) ! charge on neighbor atom
552 140848 : rhok = xcart(:,jatom)-xcart(:,iatom)
553 140848 : phase = dot_product(gvec,rhok)
554 35212 : cph = cos(phase)
555 147012 : do ii = 1, 3
556 457756 : do jj = 1, 3
557 316908 : derivs = -3.0*gvec(ii)*gvec(jj)/gsq
558 316908 : if (ii == jj) derivs = 1.0 + derivs
559 : efg_g(ii,jj,iatom) = efg_g(ii,jj,iatom) + &
560 422544 : & qk*cph*derivs*dampfac
561 : end do ! end loop over jj
562 : end do ! end loop over ii
563 : end do ! end loop over jatom
564 : end do ! end loop over iatom
565 : end if ! constrain to gsq < glkcut
566 : end if ! end selection on shell edge
567 : end if ! end avoidance of origin
568 : end do ! end loop over sz
569 : end do ! end loop over sy
570 : end do ! end loop over sx
571 : end do ! end loop over ishell
572 :
573 : !sum in real space begins here
574 :
575 : !go out enough shells such that (r*xi0)**2 is of order 30
576 50 : nshell = int(anint(sqrt(30.)/(minval(rpl)*xi0)))
577 50 : rlkcut = nshell*minval(rpl)*0.95
578 : !
579 : !go out enough shells so that rlkcut is of order 30 bohr
580 : !nshell=int(anint(30.0/minval(rpl)))
581 : !rlkcut = 0.95*nshell*minval(rpl)
582 :
583 56 : do ishell = 0, nshell ! total set of cells to loop over
584 270 : do sx = -ishell, ishell ! loop over all cells in each dimension
585 1586 : do sy = -ishell, ishell
586 10874 : do sz = -ishell, ishell
587 : ! constrain to shell surface, not interior
588 10660 : if ( abs(sx)==ishell .or. abs(sy)==ishell .or. abs(sz)==ishell ) then
589 35763 : do jatom = 1, natom ! loop over atoms in shell cell
590 212250 : do iatom = 1, natom ! loop over atoms in central unit cell
591 202916 : if (.NOT. (jatom == iatom .AND. sx == 0 .AND. sy == 0 .AND. sz == 0)) then ! avoid self term
592 172852 : qk = zion(typat(jatom)) ! charge on each neighbor atom
593 : ! ! rhored is the vector in crystal coords from neighbor to target
594 172852 : rhored(1) = xred(1,jatom) + sx - xred(1,iatom)
595 172852 : rhored(2) = xred(2,jatom) + sy - xred(2,iatom)
596 172852 : rhored(3) = xred(3,jatom) + sz - xred(3,iatom)
597 : ! ! rhok is rhored in cartesian coords
598 172852 : rhok(1) = rprimd(1,1)*rhored(1)+rprimd(1,2)*rhored(2)+rprimd(1,3)*rhored(3)
599 172852 : rhok(2) = rprimd(2,1)*rhored(1)+rprimd(2,2)*rhored(2)+rprimd(2,3)*rhored(3)
600 172852 : rhok(3) = rprimd(3,1)*rhored(1)+rprimd(3,2)*rhored(2)+rprimd(3,3)*rhored(3)
601 691408 : trace = dot_product(rhok,rhok)
602 172852 : lenrho = sqrt(trace)
603 172852 : if (lenrho < rlkcut) then ! this restriction is critical as it ensures
604 : ! ! that we sum over a sphere of atoms in real space
605 : ! ! no matter what shape the unit cell has
606 24896 : karg = xi0*lenrho
607 24896 : derfc_karg = abi_derfc(karg)
608 : ! see Honma eq. 2.10 for derivation of the following damping factor
609 24896 : dampfac = (1.0+3.0/(2.0*karg*karg))*exp(-karg*karg)+3.0*sqrt(pi)*derfc_karg/(4.0*karg**3)
610 99584 : do ii = 1, 3 ! loop over tensor elements
611 323648 : do jj = 1, 3 ! loop over tensor elements
612 224064 : derivs = -3.0*rhok(ii)*rhok(jj)/trace
613 224064 : if(ii == jj) derivs = derivs + 1.0 ! see Honma eq 4.8 re: sign
614 : ! accumulate real space tensor element,
615 : ! weighted by charge of neighbor and Ewald damping factor
616 298752 : efg_r(ii,jj,iatom) = efg_r(ii,jj,iatom) + qk*derivs*dampfac
617 : end do ! end loop over jj in efg(ii,jj,iatom)
618 : end do ! end loop over ii in efg(ii,jj,iatom)
619 : end if ! end if statement restricting to a sphere of radius rlkcut
620 : end if ! end if statement avoiding the self atom term
621 : end do ! end loop over i atoms in cell
622 : end do ! end loop over j atoms in cell
623 : end if ! end selection on outer shell of cells only
624 : end do ! end loop over sz cells
625 : end do ! end loop over sy cells
626 : end do ! end loop over sx cells
627 : end do ! end loop over shells
628 :
629 : !now combine the g-space and r-space parts, properly weighted (see Honma)
630 57 : do iatom = 1, natom
631 198 : do ii = 1, 3
632 611 : do jj = 1, 3
633 : efg(ii,jj,iatom) = four_pi*efg_g(ii,jj,iatom)/(three*ucvol)-&
634 564 : & four*xi0**3*efg_r(ii,jj,iatom)/(three*sqrt(pi))
635 : ! note extra factor of two: compare Honma eq. 4.6
636 : end do
637 : end do
638 : end do
639 :
640 : ! symmetrize tensor at each atomic site using point symmetry operations
641 57 : do iatom = 1, natom
642 57 : call matpointsym(iatom,efg(:,:,iatom),natom,nsym,rprimd,symrel,tnons,xred)
643 : end do
644 :
645 10 : ABI_FREE(efg_g)
646 10 : ABI_FREE(efg_r)
647 10 : ABI_FREE(xcart)
648 :
649 : !DEBUG
650 : !write(std_out,*)' make_efg_ion : exit '
651 : !stop
652 : !ENDDEBUG
653 :
654 10 : end subroutine make_efg_ion
655 : !!***
656 :
657 : !!****f* ABINIT/make_efg_el
658 : !! NAME
659 : !! make_efg_el
660 : !!
661 : !! FUNCTION
662 : !! compute the electric field gradient due to electron density
663 : !!
664 : !! INPUTS
665 : !! mpi_enreg=information about MPI parallelization
666 : !! natom, number of atoms in unit cell
667 : !! nfft,ngfft(18), number of FFT points and details of FFT
668 : !! nhat(nfft,nspden) compensation charge density
669 : !! nspden, number of spin components
670 : !! nsym=number of symmetries in space group
671 : !! rhor(nfft,nspden), valence electron density, here $\tilde{n} + \hat{n}$
672 : !! rprimd(3,3), conversion from crystal coordinates to cartesian coordinates
673 : !! symrel(3,3,nsym)=symmetry operators in terms of action on primitive translations
674 : !! tnons(3,nsym) = nonsymmorphic translations
675 : !! xred(3,natom), location of atoms in crystal coordinates.
676 : !!
677 : !! OUTPUT
678 : !! efg(3,3,natom), the 3x3 efg tensor at each atomic site due to rhor
679 : !!
680 : !! NOTES
681 : !! This routine computes the electric field gradient, specifically the components
682 : !! $\partial^2 V/\partial x_\alpha \partial x_\beta$ of the potential generated by the valence
683 : !! electrons, at each atomic site in the unit cell. Key references: Kresse and Joubert, ``From
684 : !! ultrasoft pseudopotentials to the projector augmented wave method'', Phys. Rev. B. 59, 1758--1775 (1999) [[cite:Kresse1999]],
685 : !! and Profeta, Mauri, and Pickard, ``Accurate first principles prediction of $^{17}$O NMR parameters in
686 : !! SiO$_2$: Assignment of the zeolite ferrierite spectrum'', J. Am. Chem. Soc. 125, 541--548 (2003) [[cite:Profeta2003]]. This
687 : !! routine computes the second derivatives of the potential generated by $\tilde{n}$ (see Kresse and Joubert
688 : !! for notation, Fourier-transforming the density, doing the sum in G space, and then transforming back at
689 : !! each atomic site. The final formula is
690 : !! \begin{displaymath}
691 : !! \frac{\partial^2 V}{\partial x_\alpha\partial x_\beta} = -4\pi^2\sum_G (G_\alpha G_\beta - \delta_{\alpha,\beta}G^2/3)
692 : !! \left(\frac{\tilde{n}(G)}{\pi G^2}\right)e^{2\pi i G\cdot R}
693 : !! \end{displaymath}
694 : !!
695 : !!
696 : !! SOURCE
697 :
698 9 : subroutine make_efg_el(efg,mpi_enreg,natom,nfft,ngfft,nhat,nspden,nsym,rhor,rprimd,symrel,tnons,xred)
699 :
700 : !Arguments ------------------------------------
701 : !scalars
702 : integer,intent(in) :: natom,nfft,nspden,nsym
703 : type(MPI_type),intent(in) :: mpi_enreg
704 : !arrays
705 : integer,intent(in) :: ngfft(18),symrel(3,3,nsym)
706 : real(dp),intent(in) :: nhat(nfft,nspden),rhor(nfft,nspden),rprimd(3,3),tnons(3,nsym),xred(3,natom)
707 : real(dp),intent(out) :: efg(3,3,natom)
708 :
709 : !Local variables-------------------------------
710 : !scalars
711 : integer :: cplex,fftdir,fofg_index,iatom,i1,i2,i2_local,i23,i3,id1,id2,id3
712 : integer :: ierr,ig,ig2,ig3,ii,ii1,ing,jj
713 : integer :: me_fft,n1,n2,n3,nproc_fft,tim_fourdp
714 : real(dp) :: cph,derivs,phase,sph,trace
715 : ! type(MPI_type) :: mpi_enreg_seq
716 : !arrays
717 : integer :: id(3)
718 9 : integer, ABI_CONTIGUOUS pointer :: fftn2_distrib(:),ffti2_local(:)
719 9 : integer, ABI_CONTIGUOUS pointer :: fftn3_distrib(:),ffti3_local(:)
720 : real(dp) :: gprimd(3,3),gqred(3),gvec(3),ratom(3)
721 9 : real(dp),allocatable :: fofg(:,:),fofr(:),gq(:,:),xcart(:,:)
722 :
723 : ! ************************************************************************
724 :
725 : !DEBUG
726 : !write(std_out,*)' make_efg_el : enter'
727 : !ENDDEBUG
728 :
729 27 : ABI_MALLOC(fofg,(2,nfft))
730 27 : ABI_MALLOC(fofr,(nfft))
731 27 : ABI_MALLOC(xcart,(3,natom))
732 :
733 542 : efg(:,:,:) = zero
734 9 : call xred2xcart(natom,rprimd,xcart,xred) ! get atomic locations in cartesian coords
735 9 : call matr3inv(rprimd,gprimd)
736 :
737 9 : tim_fourdp = 0 ! timing code, not using
738 9 : fftdir = -1 ! FT from R to G
739 9 : cplex = 1 ! fofr is real
740 : !here we are only interested in the valence pseudo charge density, which is rhor(:,1)-nhat(:,1)
741 : !regardless of the value of nspden. This may change in the future depending on
742 : !developments with noncollinear magnetization and so forth. Such a change will
743 : !require an additional loop over nspden.
744 : !Multiply by -1 to convert the electron particle density to the charge density
745 644537 : fofr(:) = -(rhor(:,1)-nhat(:,1))
746 :
747 : ! Get the distrib associated with this fft_grid See hartre.F90 for another example where
748 : ! this is done
749 9 : n1=ngfft(1); n2=ngfft(2); n3=ngfft(3)
750 9 : nproc_fft = mpi_enreg%nproc_fft; me_fft = mpi_enreg%me_fft
751 9 : call ptabs_fourdp(mpi_enreg,n2,n3,fftn2_distrib,ffti2_local,fftn3_distrib,ffti3_local)
752 :
753 9 : call fourdp(cplex,fofg,fofr,fftdir,mpi_enreg,nfft,1,ngfft,tim_fourdp) ! construct charge density in G space
754 :
755 : ! the following loops over G vectors has been copied from hartre.F90 in order to be compatible with
756 : ! possible FFT parallelism
757 :
758 : ! In order to speed the routine, precompute the components of g
759 : ! Also check if the booked space was large enough...
760 27 : ABI_MALLOC(gq,(3,max(n1,n2,n3)))
761 36 : do ii=1,3
762 27 : id(ii)=ngfft(ii)/2+2
763 1084 : do ing=1,ngfft(ii)
764 1048 : ig=ing-(ing/id(ii))*ngfft(ii)-1
765 1075 : gq(ii,ing)=ig
766 : end do
767 : end do
768 9 : id1=n1/2+2;id2=n2/2+2;id3=n3/2+2
769 :
770 : ! Triple loop on each dimension
771 309 : do i3=1,n3
772 300 : ig3=i3-(i3/id3)*n3-1
773 300 : gqred(3) = gq(3,i3)
774 :
775 13853 : do i2=1,n2
776 13544 : ig2=i2-(i2/id2)*n2-1
777 13844 : if (fftn2_distrib(i2) == me_fft) then
778 :
779 13544 : gqred(2) = gq(2,i2)
780 13544 : i2_local = ffti2_local(i2)
781 13544 : i23=n1*(i2_local-1 +(n2/nproc_fft)*(i3-1))
782 : ! Do the test that eliminates the Gamma point outside of the inner loop
783 13544 : ii1=1
784 13544 : if(i23==0 .and. ig2==0 .and. ig3==0) ii1=2
785 :
786 : ! Final inner loop on the first dimension (note the lower limit)
787 658063 : do i1=ii1,n1
788 : ! gs=gs2+ gq(1,i1)*(gq(1,i1)*gmet(1,1)+gqg2p3)
789 644519 : gqred(1) = gq(1,i1)
790 8378747 : gvec(1:3) = MATMUL(gprimd,gqred)
791 644519 : fofg_index=i1+i23
792 2578076 : trace = dot_product(gvec,gvec)
793 2591620 : do ii = 1, 3 ! sum over components of efg tensor
794 8378747 : do jj = 1, 3 ! sum over components of efg tensor
795 5800671 : derivs = gvec(ii)*gvec(jj) ! This term is $G_\alpha G_\beta$
796 5800671 : if (ii == jj) derivs = derivs - trace/three
797 34391427 : do iatom = 1, natom ! sum over atoms in unit cell
798 106628796 : ratom(:) = xcart(:,iatom) ! extract location of atom iatom
799 106628796 : phase = two_pi*dot_product(gvec,ratom) ! argument of $e^{2\pi i G\cdot R}$
800 26657199 : cph = cos(phase)
801 26657199 : sph = sin(phase)
802 : efg(ii,jj,iatom) = efg(ii,jj,iatom) - &
803 32457870 : & four_pi*derivs*(fofg(1,fofg_index)*cph-fofg(2,fofg_index)*sph)/trace ! real part of efg tensor
804 : end do ! end loop over atoms in cell
805 : end do ! end loop over jj in V_ij
806 : end do ! end loop over ii in V_ij
807 : end do ! End loop on i1
808 : end if
809 : end do ! End loop on i2
810 : end do ! End loop on i3
811 :
812 9 : call xmpi_sum(efg,mpi_enreg%comm_fft,ierr)
813 :
814 : ! symmetrize tensor at each atomic site using point symmetry operations
815 50 : do iatom = 1, natom
816 50 : call matpointsym(iatom,efg(:,:,iatom),natom,nsym,rprimd,symrel,tnons,xred)
817 : end do
818 :
819 9 : ABI_FREE(fofg)
820 9 : ABI_FREE(fofr)
821 9 : ABI_FREE(xcart)
822 9 : ABI_FREE(gq)
823 :
824 : !DEBUG
825 : !write(std_out,*)' make_efg_el : exit '
826 : !stop
827 : !ENDDEBUG
828 :
829 9 : end subroutine make_efg_el
830 : !!***
831 :
832 : end module m_nucprop
833 : !!***
|