TABLE OF CONTENTS


ABINIT/partial_dos_fractions [ Functions ]

[ Top ] [ Functions ]

NAME

 partial_dos_fractions

FUNCTION

 calculate partial DOS fractions to feed to the tetrahedron method
  1: project states on angular momenta
  2: should be able to choose certain atoms or atom types, slabs of space...

COPYRIGHT

 Copyright (C) 1998-2018 ABINIT group (MVer,MB,MG)
 This file is distributed under the terms of the
 GNU General Public License, see ~abinit/COPYING
 or http://www.gnu.org/copyleft/gpl.txt .
 For the initials of contributors, see ~abinit/doc/developers/contributors.txt .

INPUTS

  crystal<crystal_t>= data type gathering info on symmetries and unit cell
  dtset<type(dataset_type)>=all input variables for this dataset
  npwarr(nkpt)=number of planewaves in basis at this k point
  kg(3,mpw*mkmem)=reduced planewave coordinates.
  cg(2,mcg)=planewave coefficients of wavefunctions
  mcg=size of wave-functions array (cg) =mpw*nspinor*mband*mkmem*nsppol
  collect=1 if fractions should be MPI collected at the end, 0 otherwise.
  mpi_enreg=information about MPI parallelization

SIDE EFFECTS

  dos%fractions(ikpt,iband,isppol,ndosfraction) = percentage of s, p, d..
    character on each atom for the wavefunction # ikpt,iband, isppol
  == if prtdosm /= 0
  dos%fractions_m(ikpt,iband,isppol,ndosfraction*mbesslang) = percentage of s, p, d..
    character on each atom for the wavefunction # ikpt,iband, isppol (m-resolved)

NOTES

   psi(r) = (4pi/sqrt(ucvol)) \sum_{LMG} i**l u(G) e^{i(k+G).Ra} x Y_{LM}^*(k+G) Y_{LM}(r-Ra) j_L(|k+G||r-Ra|)

   int_(ratsph) |psi(r)|**2 = \sum_LM rho(LM)

   where

   rho_{LM} = 4pi \int_o^{rc} dr r**2 ||\sum_G u(G) Y_LM^*(k+G) e^{i(k+G).Ra} j_L(|k+G| r)||**2

   where S is a RSH. The final expression is:

   When k = G0/2, we have u_{G0/2}(G) = u_{G0/2}(-G-G0)^* and P can be rewritten as

     P = (4pi i^L}/sqrt(ucvol) \sum^'_G w(G) S_{LM}(k+G) \int_0^ratsph dr r^2 j_L(|k+G|r) x
                                  2 Re[u_k(G) e^{i(k+G).R_atom}]  if L = 2n
                                  2 Im[u_k(G) e^{i(k+G).R_atom}]  if L = 2n + 1

  where the sum over G is done on the reduced G-sphere and w(G) = 1/2 if G=G0 else 1.

PARENTS

      outscfcv

CHILDREN

      cg_getspin,cwtime,destroy_mpi_enreg,getkpgnorm,getph,initmpi_seq
      initylmg,jlspline_free,ph1d3d,recip_ylm,sort_dp,splint,wrtout,xmpi_sum

SOURCE

 64 #if defined HAVE_CONFIG_H
 65 #include "config.h"
 66 #endif
 67 
 68 #include "abi_common.h"
 69 
 70 subroutine partial_dos_fractions(dos,crystal,dtset,npwarr,kg,cg,mcg,collect,mpi_enreg)
 71 
 72  use defs_basis
 73  use defs_abitypes
 74  use m_profiling_abi
 75  use m_errors
 76  use m_splines
 77  use m_xmpi
 78  use m_mpinfo
 79  use m_crystal
 80  use m_sort
 81 
 82  use m_time,          only : cwtime
 83  use m_numeric_tools, only : simpson
 84  use m_special_funcs, only : jlspline_t, jlspline_new, jlspline_free, jlspline_integral
 85  use m_cgtools,       only : cg_getspin
 86  use m_epjdos,        only : recip_ylm, epjdos_t
 87  use m_gsphere,       only : getkpgnorm
 88  use m_kg,            only : ph1d3d, getph
 89 
 90 !This section has been created automatically by the script Abilint (TD).
 91 !Do not modify the following lines by hand.
 92 #undef ABI_FUNC
 93 #define ABI_FUNC 'partial_dos_fractions'
 94  use interfaces_14_hidewrite
 95  use interfaces_32_util
 96  use interfaces_51_manage_mpi
 97  use interfaces_56_recipspace
 98 !End of the abilint section
 99 
100  implicit none
101 
102 !Arguments ------------------------------------
103 !scalars
104  integer,intent(in) :: mcg,collect
105  type(epjdos_t),intent(inout) :: dos
106  type(MPI_type),intent(inout) :: mpi_enreg
107  type(dataset_type),intent(in) :: dtset
108  type(crystal_t),intent(in) :: crystal
109 !arrays
110  integer,intent(in) :: kg(3,dtset%mpw*dtset%mkmem),npwarr(dtset%nkpt)
111  real(dp),intent(in) :: cg(2,mcg)
112 
113 !Local variables-------------------------------
114 !scalars
115  integer,parameter :: prtsphere0=0 ! do not output all the band by band details for projections.
116  integer :: shift_b,shift_sk,iat,iatom,iband,ierr,ikpt,ilang,ioffkg,is1, is2, isoff
117  integer :: ipw,ispinor,isppol,ixint,mbess,mcg_disk,me_kpt,shift_cg
118  integer :: me_g0,mgfft,my_nspinor,n1,n2,n3,natsph_tot,npw_k,nradintmax
119  integer :: comm_pw,comm_kpt,rc_ylm,itypat,nband_k
120  real(dp),parameter :: bessint_delta = 0.1_dp
121  real(dp) :: arg,bessarg,bessargmax,kpgmax,rmax
122  real(dp) :: cpu,wall,gflops
123  character(len=500) :: msg
124  type(jlspline_t) :: jlspl
125  type(MPI_type) :: mpi_enreg_seq
126 !arrays
127  integer :: iindex(dtset%mpw),nband_tmp(1),npwarr_tmp(1)
128  integer,allocatable :: iatsph(:),nradint(:),atindx(:),typat_extra(:),kg_k(:,:)
129  real(dp) :: kpoint(3),spin(3),ylmgr_dum(1)
130  real(dp) :: xfit(dtset%mpw),yfit(dtset%mpw)
131  real(dp),allocatable :: ylm_k(:,:)
132  real(dp),allocatable :: bess_fit(:,:,:)
133  real(dp),allocatable :: cg_1band(:,:),cg_1kpt(:,:),kpgnorm(:),ph1d(:,:)
134  real(dp),allocatable :: ph3d(:,:,:),ratsph(:),rint(:),sum_1atom_1ll(:,:)
135  real(dp),allocatable :: sum_1atom_1lm(:,:)
136  real(dp),allocatable :: xred_sph(:,:),znucl_sph(:),phkxred(:,:)
137  complex(dpc) :: cgcmat(2,2)
138 
139 !*************************************************************************
140 
141  ! for the moment, only support projection on angular momenta
142  if (dos%partial_dos_flag /= 1 .and. dos%partial_dos_flag /= 2) then
143    write(std_out,*) 'Error: partial_dos_fractions only supports angular '
144    write(std_out,*) ' momentum projection and spinor components for the moment. return to outscfcv'
145    write(std_out,*) ' partial_dos = ', dos%partial_dos_flag
146    return
147  end if
148 
149  ! impose all kpoints have same number of bands
150  do isppol=1,dtset%nsppol
151    do ikpt=1,dtset%nkpt
152      if (dtset%nband((isppol-1)*dtset%nkpt + ikpt) /= dtset%mband) then
153        write(std_out,*) 'Error: partial_dos_fractions wants same number of bands at each kpoint'
154        write(std_out,*) ' isppol, ikpt = ', isppol,ikpt, dtset%nband((isppol-1)*dtset%nkpt + ikpt), dtset%mband
155        write(std_out,*) ' all nband = ', dtset%nband
156        return
157      end if
158    end do
159  end do
160 
161  ! Real or complex spherical harmonics?
162  rc_ylm = 2; if (dos%prtdosm == 2) rc_ylm = 1
163 
164  comm_kpt = mpi_enreg%comm_kpt
165  me_kpt = mpi_enreg%me_kpt
166  comm_pw = mpi_enreg%comm_bandfft ; me_g0 = mpi_enreg%me_g0
167  my_nspinor = max(1,dtset%nspinor/mpi_enreg%nproc_spinor)
168 
169  n1 = dtset%ngfft(1); n2 = dtset%ngfft(2); n3 = dtset%ngfft(3)
170  mgfft = maxval(dtset%ngfft(1:3))
171 
172  call cwtime(cpu, wall, gflops, "start")
173 
174 !##############################################################
175 !FIRST CASE: project on angular momenta to get dos parts
176 !##############################################################
177 
178  if (dos%partial_dos_flag == 1) then
179    natsph_tot = dtset%natsph + dtset%natsph_extra
180 
181    ABI_ALLOCATE(iatsph, (natsph_tot))
182    ABI_ALLOCATE(typat_extra, (natsph_tot))
183    ABI_ALLOCATE(ratsph, (natsph_tot))
184    ABI_ALLOCATE(znucl_sph, (natsph_tot))
185    ABI_ALLOCATE(nradint, (natsph_tot))
186    ABI_ALLOCATE(atindx, (natsph_tot))
187    ABI_ALLOCATE(phkxred, (2,natsph_tot))
188 
189    ! initialize atindx
190    do iatom=1,natsph_tot
191      atindx(iatom) = iatom
192    end do
193 
194    iatsph(1:dtset%natsph) = dtset%iatsph(1:dtset%natsph)
195    do iatom=1,dtset%natsph
196      itypat = dtset%typat(iatsph(iatom))
197      typat_extra(iatom) = itypat
198      ratsph(iatom) = dtset%ratsph(itypat)
199      znucl_sph(iatom) = dtset%znucl(itypat)
200    end do
201 
202    ! fictitious atoms are declared with
203    ! %natsph_extra, %ratsph_extra and %xredsph_extra(3, dtset%natsph_extra)
204    ! they have atom index (natom + ii) and itype = ntypat + 1
205    do iatom=1,dtset%natsph_extra
206      typat_extra(iatom+dtset%natsph) = dtset%ntypat + 1
207      ratsph(iatom+dtset%natsph) = dtset%ratsph_extra
208      znucl_sph(iatom+dtset%natsph) = zero
209      iatsph(iatom+dtset%natsph) = dtset%natom + iatom
210    end do
211 
212    ! init bessel function integral for recip_ylm max ang mom + 1
213    ABI_ALLOCATE(sum_1atom_1ll,(dos%mbesslang,natsph_tot))
214    ABI_ALLOCATE(sum_1atom_1lm,(dos%mbesslang**2,natsph_tot))
215 
216    ! Note ecuteff instead of ecut.
217    kpgmax = sqrt(dtset%ecut * dtset%dilatmx**2)
218    rmax = zero; bessargmax = zero; nradintmax = 0
219    do iatom=1,natsph_tot
220      rmax = max(rmax, ratsph(iatom))
221      bessarg = ratsph(iatom)*two_pi*kpgmax
222      bessargmax = max(bessargmax, bessarg)
223      nradint(iatom) = int (bessarg / bessint_delta) + 1
224      nradintmax = max(nradintmax,nradint(iatom))
225    end do
226    !write(std_out,*)' partial_dos_fractions: rmax=', rmax,' nradintmax: ", nradintmax
227 !  use same number of grid points to calculate Bessel function and to do the integration later on r
228 !  and make sure bessargmax is a multiple of bessint_delta
229    mbess = nradintmax
230    bessargmax = bessint_delta*mbess
231 
232    ABI_ALLOCATE(rint,(nradintmax))
233    ABI_ALLOCATE(bess_fit,(dtset%mpw,nradintmax,dos%mbesslang))
234 
235    ! initialize general Bessel function array on uniform grid xx, from 0 to (2 \pi |k+G|_{max} |r_{max}|)
236    jlspl = jlspline_new(mbess, bessint_delta, dos%mbesslang)
237 
238    ABI_ALLOCATE(xred_sph, (3, natsph_tot))
239    do iatom=1,dtset%natsph
240      xred_sph(:,iatom) = crystal%xred(:,iatsph(iatom))
241    end do
242    do iatom=1,dtset%natsph_extra
243      xred_sph(:,dtset%natsph+iatom) = dtset%xredsph_extra(:, iatom)
244    end do
245 
246    ABI_ALLOCATE(ph1d,(2,(2*n1+1 + 2*n2+1 + 2*n3+1)*natsph_tot))
247    call getph(atindx,natsph_tot,n1,n2,n3,ph1d,xred_sph)
248 
249    ! Fake MPI data to be used for sequential call to initylmg.
250    call initmpi_seq(mpi_enreg_seq)
251    mpi_enreg_seq%my_natom = dtset%natom
252 
253    shift_sk = 0
254    do isppol=1,dtset%nsppol
255      ioffkg = 0
256      do ikpt=1,dtset%nkpt
257        nband_k = dtset%nband((isppol-1)*dtset%nkpt + ikpt)
258        if (proc_distrb_cycle(mpi_enreg%proc_distrb,ikpt,1,nband_k,isppol,me_kpt)) cycle
259        npw_k = npwarr(ikpt)
260        kpoint(:) = dtset%kpt(:,ikpt)
261 
262        ! make phkred for all atoms
263        do iat=1,natsph_tot
264          arg=two_pi*( kpoint(1)*xred_sph(1,iat) + kpoint(2)*xred_sph(2,iat) + kpoint(3)*xred_sph(3,iat) )
265          phkxred(1,iat)=cos(arg)
266          phkxred(2,iat)=sin(arg)
267        end do
268 
269        ABI_MALLOC(kg_k, (3, npw_k))
270        kg_k = kg(:,ioffkg+1:ioffkg+npw_k)
271 
272        ! kpgnorm contains norms only for kpoints used by this processor
273        ABI_ALLOCATE(kpgnorm, (npw_k))
274        call getkpgnorm(crystal%gprimd, kpoint, kg_k, kpgnorm, npw_k)
275 
276        ! Now get Ylm(k, G) factors: returns "real Ylms", which are real (+m) and
277        ! imaginary (-m) parts of actual complex Ylm. Yl-m = Ylm*
278        ! Call initylmg for a single k-point (mind mpi_enreg_seq).
279        ABI_MALLOC(ylm_k, (npw_k, dos%mbesslang**2))
280        npwarr_tmp(1) = npw_k; nband_tmp(1) = nband_k
281        call initylmg(crystal%gprimd,kg_k,kpoint,1,mpi_enreg_seq,dos%mbesslang,&
282        npw_k,nband_tmp,1,npwarr_tmp,1,0,crystal%rprimd,ylm_k,ylmgr_dum)
283 
284        ! get phases exp (2 pi i (k+G).x_tau) in ph3d
285        ABI_ALLOCATE(ph3d,(2,npw_k,natsph_tot))
286        call ph1d3d(1,natsph_tot,kg_k,natsph_tot,natsph_tot,npw_k,n1,n2,n3,phkxred,ph1d,ph3d)
287 
288        ! get Bessel function factors on array of |k+G|*r distances
289        ! since we need many r distances and have a large number of different
290        ! |k+G|, get j_l on uniform grid (above, in array gen_besj),
291        ! and spline it for each kpt Gvector set.
292        ! Note that we use the same step based on rmax, this can lead to (hopefully small)
293        ! inaccuracies when we integrate from 0 up to rmax(iatom)
294        do ixint=1,nradintmax
295          rint(ixint) = (ixint-1)*rmax / (nradintmax-1)
296          do ipw=1,npw_k
297            xfit(ipw) = two_pi * kpgnorm(ipw) * rint(ixint)
298            iindex(ipw) = ipw
299          end do
300 
301          call sort_dp(npw_k,xfit,iindex,tol14)
302          do ilang=1,dos%mbesslang
303            call splint(mbess, jlspl%xx, jlspl%bess_spl(:,ilang), jlspl%bess_spl_der(:,ilang), npw_k, xfit, yfit)
304            ! re-order results for different G vectors
305            do ipw=1,npw_k
306              bess_fit(iindex(ipw),ixint,ilang) = yfit(ipw)
307            end do
308          end do
309        end do ! ixint
310 
311        shift_b = 0
312        do iband=1,nband_k
313          if (proc_distrb_cycle(mpi_enreg%proc_distrb,ikpt,iband,iband,isppol,me_kpt)) cycle
314          !write(std_out,*)"in band:",iband
315 
316          do ispinor=1,my_nspinor
317            ! Select wavefunction in cg array
318            shift_cg = shift_sk + shift_b
319 
320            call recip_ylm(bess_fit, cg(:,shift_cg+1:shift_cg+npw_k), comm_pw, dtset%istwfk(ikpt),&
321 &           nradint, nradintmax, me_g0, dos%mbesslang , dtset%mpw, natsph_tot, typat_extra, dos%mlang_type,&
322 &           npw_k,ph3d, prtsphere0, rint, ratsph, rc_ylm, sum_1atom_1ll, sum_1atom_1lm,&
323 &           crystal%ucvol, ylm_k, znucl_sph)
324 
325            ! Accumulate
326            do iatom=1,natsph_tot
327              do ilang=1,dos%mbesslang
328                dos%fractions(ikpt,iband,isppol,dos%mbesslang*(iatom-1) + ilang) &
329 &               = dos%fractions(ikpt,iband,isppol,dos%mbesslang*(iatom-1) + ilang) &
330 &               + sum_1atom_1ll(ilang,iatom)
331              end do
332            end do
333 
334            if (dos%prtdosm /= 0) then
335              do iatom=1,natsph_tot
336                do ilang=1,dos%mbesslang**2
337                  dos%fractions_m(ikpt,iband,isppol,dos%mbesslang**2*(iatom-1) + ilang) &
338 &                 = dos%fractions_m(ikpt,iband,isppol,dos%mbesslang**2*(iatom-1) + ilang) &
339 &                 + sum_1atom_1lm(ilang,iatom)
340                end do
341              end do
342            end if
343 
344            ! Increment band, spinor shift
345            shift_b = shift_b + npw_k
346          end do ! spinor
347        end do ! band
348 
349        ! Increment kpt and (spin, kpt) shifts
350        ioffkg = ioffkg + npw_k
351        shift_sk = shift_sk + nband_k*my_nspinor*npw_k
352 
353        ABI_FREE(kg_k)
354        ABI_FREE(kpgnorm)
355        ABI_FREE(ylm_k)
356        ABI_DEALLOCATE(ph3d)
357      end do ! ikpt
358    end do ! isppol
359 
360    ! collect = 1 ==> gather all contributions from different processors
361    if (collect == 1) then
362      call xmpi_sum(dos%fractions,comm_kpt,ierr)
363      if (dos%prtdosm /= 0) call xmpi_sum(dos%fractions_m,comm_kpt,ierr)
364 
365      if (mpi_enreg%paral_spinor == 1)then
366        call xmpi_sum(dos%fractions,mpi_enreg%comm_spinor,ierr)
367        if (dos%prtdosm /= 0) call xmpi_sum(dos%fractions_m,mpi_enreg%comm_spinor,ierr)
368      end if
369    end if
370 
371    ABI_DEALLOCATE(atindx)
372    ABI_DEALLOCATE(bess_fit)
373    ABI_DEALLOCATE(iatsph)
374    ABI_DEALLOCATE(typat_extra)
375    ABI_DEALLOCATE(nradint)
376    ABI_DEALLOCATE(ph1d)
377    ABI_DEALLOCATE(phkxred)
378    ABI_DEALLOCATE(ratsph)
379    ABI_DEALLOCATE(rint)
380    ABI_DEALLOCATE(sum_1atom_1ll)
381    ABI_DEALLOCATE(sum_1atom_1lm)
382    ABI_DEALLOCATE(xred_sph)
383    ABI_DEALLOCATE(znucl_sph)
384 
385    call jlspline_free(jlspl)
386    call destroy_mpi_enreg(mpi_enreg_seq)
387 
388  !##############################################################
389  !2ND CASE: project on spinors
390  !##############################################################
391 
392  else if (dos%partial_dos_flag == 2) then
393 
394    if (dtset%nsppol /= 1 .or. dtset%nspinor /= 2) then
395      MSG_WARNING("spinor projection is meaningless if nsppol==2 or nspinor/=2. Not calculating projections.")
396      return
397    end if
398    if (my_nspinor /= 2) then
399      MSG_WARNING("spinor projection with spinor parallelization is not coded. Not calculating projections.")
400      return
401    end if
402    ABI_CHECK(mpi_enreg%paral_spinor == 0, "prtdos 5 does not support spinor parallelism")
403 
404    ! FIXME: We should not allocate such a large chunk of memory!
405    mcg_disk = dtset%mpw*my_nspinor*dtset%mband
406    ABI_ALLOCATE(cg_1kpt,(2,mcg_disk))
407    shift_sk = 0
408    isppol = 1
409 
410    do ikpt=1,dtset%nkpt
411      nband_k = dtset%nband((isppol-1)*dtset%nkpt + ikpt)
412      if (proc_distrb_cycle(mpi_enreg%proc_distrb,ikpt,1,nband_k,isppol,me_kpt)) cycle
413      npw_k = npwarr(ikpt)
414 
415      cg_1kpt(:,:) = cg(:,shift_sk+1:shift_sk+mcg_disk)
416      ABI_ALLOCATE(cg_1band,(2,2*npw_k))
417      shift_b=0
418      do iband=1,nband_k
419        if (proc_distrb_cycle(mpi_enreg%proc_distrb,ikpt,iband,iband,isppol,me_kpt)) cycle
420 
421        ! Select wavefunction in cg array
422        !shift_cg = shift_sk + shift_b
423        cg_1band(:,:) = cg_1kpt(:,shift_b+1:shift_b+2*npw_k)
424        call cg_getspin(cg_1band, npw_k, spin, cgcmat=cgcmat)
425 
426        ! MG: TODO: imag part of off-diagonal terms is missing.
427        ! I will add them later on.
428        do is1=1,2
429          do is2=1,2
430            isoff = is2 + (is1-1)*2
431            dos%fractions(ikpt,iband,isppol,isoff) = dos%fractions(ikpt,iband,isppol,isoff) &
432 &           + real(cgcmat(is1,is2))
433          end do
434        end do
435 
436        dos%fractions(ikpt,iband,isppol,5) = dos%fractions(ikpt,iband,isppol,5) + spin(1)
437        dos%fractions(ikpt,iband,isppol,6) = dos%fractions(ikpt,iband,isppol,6) + spin(2)
438        dos%fractions(ikpt,iband,isppol,7) = dos%fractions(ikpt,iband,isppol,7) + spin(3)
439 
440        shift_b = shift_b + 2*npw_k
441      end do
442      ABI_DEALLOCATE(cg_1band)
443      shift_sk = shift_sk + nband_k*2*npw_k
444    end do
445    ABI_DEALLOCATE(cg_1kpt)
446 
447    ! Gather all contributions from different processors
448    if (collect == 1) then
449      call xmpi_sum(dos%fractions,comm_kpt,ierr)
450      call xmpi_sum(dos%fractions,comm_pw,ierr)
451      !below for future use - spinors should not be parallelized for the moment
452      !if (mpi_enreg%paral_spinor == 1)then
453      !  call xmpi_sum(dos%fractions,mpi_enreg%comm_spinor,ierr)
454      !end if
455    end if
456 
457  else
458    MSG_WARNING('only partial_dos==1 or 2 is coded')
459  end if
460 
461  call cwtime(cpu,wall,gflops,"stop")
462  write(msg,'(2(a,f8.2),a)')" partial_dos_fractions: cpu_time: ",cpu,"[s], walltime: ",wall," [s]"
463  call wrtout(std_out,msg,"PERS")
464 
465 end subroutine partial_dos_fractions