LCOV - code coverage report
Current view: top level - vgen - vgen_coulomb.F90 (source / functions) Coverage Total Hit
Test: FLEUR test coverage Lines: 73.0 % 126 92
Test Date: 2025-06-14 04:34:23 Functions: 50.0 % 2 1

            Line data    Source code
       1              : !--------------------------------------------------------------------------------
       2              : ! Copyright (c) 2016 Peter Grünberg Institut, Forschungszentrum Jülich, Germany
       3              : ! This file is part of FLEUR and available as free software under the conditions
       4              : ! of the MIT license as expressed in the LICENSE file in more detail.
       5              : !--------------------------------------------------------------------------------
       6              : 
       7              : module m_vgen_coulomb
       8              : 
       9              :   use m_juDFT
      10              : #ifdef CPP_MPI
      11              :   use mpi
      12              : #endif
      13              : contains
      14              : 
      15          682 :   subroutine vgen_coulomb( ispin, fmpi,    input, field, vacuum, sym, juphon, stars, &
      16              :              cell, sphhar, atoms, dosf, den, vCoul, sigma_disc, results, dfptdenimag, dfptvCoulimag, dfptden0, stars2, iDtype, iDir, iDir2, sigma_disc2 )
      17              :     !----------------------------------------------------------------------------
      18              :     ! FLAPW potential generator
      19              :     !----------------------------------------------------------------------------
      20              :     ! Generates the Coulomb or Yukawa potential and optionally the
      21              :     ! density-potential integrals
      22              :     ! vCoul%potdenType = POTDEN_TYPE_POTYUK -> Yukawa case
      23              :     ! It takes a spin variable to indicate in which spin-channel the charge
      24              :     ! resides.
      25              :     !----------------------------------------------------------------------------
      26              : 
      27              :     use m_constants
      28              :     use m_types
      29              :     use m_vmts
      30              :     use m_intnv
      31              :     use m_vvac
      32              :     use m_vvacis
      33              :     use m_vvacxy
      34              :     use m_vintcz
      35              :     use m_checkdopall
      36              :     use m_convol
      37              :     use m_psqpw
      38              :     use m_cfft
      39              :     implicit none
      40              : 
      41              :     integer,            intent(in)               :: ispin
      42              :     type(t_mpi),        intent(in)               :: fmpi
      43              : 
      44              :      
      45              :     type(t_input),      intent(in)               :: input
      46              :     type(t_field),      intent(in)               :: field
      47              :     type(t_vacuum),     intent(in)               :: vacuum
      48              :     type(t_sym),        intent(in)               :: sym
      49              :     type(t_juphon),     intent(in)               :: juphon
      50              :     type(t_stars),      intent(in)               :: stars
      51              :     type(t_cell),       intent(in)               :: cell
      52              :     type(t_sphhar),     intent(in)               :: sphhar
      53              :     type(t_atoms),      intent(in)               :: atoms
      54              :     LOGICAL,            INTENT(IN)               :: dosf
      55              :     type(t_potden),     intent(in)               :: den
      56              :     type(t_potden),     intent(inout)            :: vCoul
      57              :     COMPLEX,            INTENT(INOUT)            :: sigma_disc(2)
      58              :     type(t_results),    intent(inout), optional  :: results
      59              : 
      60              :     TYPE(t_potden),     OPTIONAL, INTENT(IN)     :: dfptdenimag,  dfptden0
      61              :     TYPE(t_potden),     OPTIONAL, INTENT(INOUT)  :: dfptvCoulimag
      62              :     TYPE(t_stars),      OPTIONAL, INTENT(IN)     :: stars2
      63              :     INTEGER, OPTIONAL, INTENT(IN)                :: iDtype, iDir ! DFPT: Type and direction of displaced atom
      64              :     INTEGER, OPTIONAL, INTENT(IN)                :: iDir2 ! DFPT: 2nd direction for 2nd order VC
      65              :     COMPLEX, OPTIONAL, INTENT(IN)                :: sigma_disc2(2)
      66              : 
      67              :     complex                                      :: vintcza, xint, rhobar,vslope
      68              :     integer                                      :: i, i3, irec2, irec3, ivac, j, js, k, k3
      69              :     integer                                      :: lh, n, nzst1, first_star
      70              :     integer                                      :: imz, imzxy, ichsmrg, ivfft
      71              :     integer                                      :: l, nat
      72              :     real                                         :: ani, g3, z
      73              :     complex                                      :: sig1dh, vz1dh, vmz1dh, vmz1dh_is, constantShift
      74              :     complex                                      :: mat2ord(5,3,3), sigma_loc(2), sigma_loc2(2)
      75          682 :     complex, allocatable                         :: alphm(:,:), psq(:)
      76          682 :     real,    allocatable                         :: af1(:), bf1(:)
      77              :     real                                         :: gaussian, sigma ! smoothing function in case of DFPT + Film 
      78              :     LOGICAL :: l_dfptvgen ! If this is true, we handle things differently!
      79              :     LOGICAL :: l_2ndord, l_corr
      80              : 
      81              : #ifdef CPP_MPI
      82              :     integer:: ierr
      83              : #endif
      84              : 
      85          682 :     l_dfptvgen = PRESENT(stars2)
      86          682 :     l_2ndord = PRESENT(iDir2)
      87          682 :     l_corr = .FALSE. !ALL(ABS(den%vac)<1e-12)
      88          682 :     vmz1dh_is = cmplx(0.0,0.0)
      89          682 :     sigma_loc = CMPLX(0.0,0.0) !sigma_disc
      90          682 :     sigma_loc2 = CMPLX(0.0,0.0) !MERGE(sigma_disc,cmplx(0.0,0.0),PRESENT(sigma_disc2))
      91              : 
      92          682 :     vintcza = cmplx(0.0,0.0)
      93          682 :     sig1dh = cmplx(0.0,0.0)
      94          682 :     vz1dh = cmplx(0.0,0.0)
      95          682 :     vmz1dh = cmplx(0.0,0.0)
      96          682 :     vslope = cmplx(0.0,0.0)
      97          682 :     constantShift = cmplx(0.0,0.0)
      98              : 
      99          682 :     allocate ( alphm(stars%ng2,2), af1(3*stars%mx3), bf1(3*stars%mx3), psq(stars%ng3)  )
     100          682 :     sigma = (cell%amat(3,3) - 2*cell%z1)/8.0
     101          682 :     vCoul%iter = den%iter
     102              : 
     103              :     ! PSEUDO-CHARGE DENSITY COEFFICIENTS
     104          682 :     call timestart( "psqpw" )
     105          682 :     if (.not.l_dfptvgen) then
     106              :         call psqpw( fmpi, atoms, sphhar, stars, vacuum,  cell, input, sym,   &
     107          682 :             & juphon, den, ispin, .false., vCoul%potdenType, psq, sigma_loc )
     108            0 :     else if (.not.l_2ndord) then
     109              :         ! If we do DFPT, the MT density perturbation has an imaginary part that needs to be explicitly carried
     110              :         ! as another variable dfptdenimag%mt and results in the same component for the Coulomb potential later on.
     111              :         ! Also, the ionic qlm behave differently.
     112              :         call psqpw( fmpi, atoms, sphhar, stars, vacuum,  cell, input, sym,   &
     113              :             & juphon, den, ispin, .false., vCoul%potdenType, psq, sigma_loc,&
     114            0 :             & dfptdenimag%mt(:,:,:,ispin), stars2, iDtype, iDir, dfptden0%mt(:,:,:,ispin), dfptden0%pw(:,ispin) )
     115              :     else
     116            0 :         call make_mat_2nd(mat2ord)
     117              :         call psqpw( fmpi, atoms, sphhar, stars, vacuum,  cell, input, sym,   &
     118              :             & juphon, den, ispin, .false., vCoul%potdenType, psq, sigma_loc,&
     119            0 :             & dfptdenimag%mt(:,:,:,ispin), stars2, iDtype, iDir, dfptden0%mt(:,:,:,ispin), dfptden0%pw(:,ispin), iDir2, mat2ord )
     120              :     end if
     121          682 :     call timestop( "psqpw" )
     122              : 
     123              :     ! VACUUM POTENTIAL
     124          682 :     if ( fmpi%irank == 0 ) then
     125          341 :       if ( input%film ) then
     126              :         !     ----> potential in the  vacuum  region
     127           37 :         call timestart( "Vacuum" )
     128          148 :         if ((.not.l_dfptvgen).or.norm2(stars%center)<1e-8) then
     129              :           ! If we do DPFT AND q/=0, there is no G_||+q_||=0 part! So all components are
     130              :           ! handled by the G_||/=0 parts in vvacis/vvacxy, that are told to explicitly
     131              :           ! start at star 1 instead of 2 for this!
     132           37 :           if (.not.l_2ndord) then
     133              :             !call vvac( vacuum, stars, cell,  input, field, psq, den%vac(:,1,:,ispin), vCoul%vac(:,1,:,ispin), rhobar, sig1dh, vz1dh,vslope,.FALSE..AND.l_dfptvgen,vmz1dh,sigma_disc )
     134           37 :             call vvac( vacuum, stars, cell,  input, field, psq, den%vac(:,1,:,ispin), vCoul%vac(:,1,:,ispin), rhobar, sig1dh, vz1dh,vslope,l_corr,vmz1dh,sigma_disc )
     135              :           else
     136              :             !call vvac( vacuum, stars, cell,  input, field, psq, den%vac(:,1,:,ispin), vCoul%vac(:,1,:,ispin), rhobar, sig1dh, vz1dh,vslope,.TRUE.,vmz1dh,sigma_disc,sigma_disc2 )
     137            0 :             call vvac( vacuum, stars, cell,  input, field, psq, den%vac(:,1,:,ispin), vCoul%vac(:,1,:,ispin), rhobar, sig1dh, vz1dh,vslope,l_corr,vmz1dh,sigma_disc,sigma_disc2 )
     138              :           end if
     139              :         end if
     140           37 :         call vvacis( stars, vacuum, cell, psq, input, field, vCoul%vac(:vacuum%nmzxyd,:,:,ispin), l_dfptvgen, l_corr )
     141           37 :         call vvacxy( stars, vacuum, cell, sym, input, field, den%vac(:vacuum%nmzxyd,:,:,ispin), vCoul%vac(:vacuum%nmzxyd,:,:,ispin), alphm, l_dfptvgen )
     142           37 :         call timestop( "Vacuum" )
     143           37 :         if ( l_dfptvgen .AND. juphon%l_symVacLevel ) constantShift =  (vCoul%vac(vacuum%nmzd,1,1,ispin)  - vCoul%vac(vacuum%nmzd,1,2,ispin)) / 2
     144              :       end if
     145              : 
     146              :       ! INTERSTITIAL POTENTIAL
     147          341 :       call timestart( "interstitial" )
     148          341 :       write(oUnit, fmt=8010 )
     149              : 8010  format (/,5x,'coulomb potential in the interstitial region:')
     150              :       ! in case of a film:
     151          341 :       if ( input%film ) then
     152              :         ! create v(z) for each 2-d reciprocal vector
     153           37 :         ivfft = 3 * stars%mx3
     154           37 :         ani = 1.0 / real( ivfft )
     155        13487 :         do irec2 = 1, stars%ng2
     156              :           ! If we do DFPT, we want to fix the second vacuum at infinity to 0. This is WIP,
     157              :           ! as to how we want to do it eventually. Here, we calculate the necessary offset.
     158              :           !IF (l_dfptvgen.AND.irec2 == 1) vmz1dh_is = vintcz( stars, vacuum, cell,  input, field, -cell%z1+1e-15, irec2, psq, &
     159              :           !                    vCoul%vac(:,:,:,ispin), &
     160              :           !                    rhobar, sig1dh, vz1dh, alphm, vslope, .TRUE., CMPLX(0.0,0.0) )
     161        13450 :           i = 0
     162       532435 :           do i3 = 0, ivfft - 1
     163       518985 :             i = i + 1
     164       518985 :             z = cell%amat(3,3) * i3 * ani
     165       518985 :             if (l_dfptvgen) gaussian = 1 - exp( -(z-cell%amat(3,3)/2.0)**2 / ( 2 * sigma**2 )    )
     166       518985 :             if ( z > cell%amat(3,3) / 2. ) z = z - cell%amat(3,3)
     167       518985 :             if (.not.l_2ndord) then
     168              :               vintcza = vintcz( stars, vacuum, cell,  input, field, z, irec2, psq, &
     169              :                                 vCoul%vac(:,:,:,ispin), &
     170       518985 :                                 rhobar, sig1dh, vz1dh, alphm, vslope, sigma_disc, l_dfptvgen, l_corr, vmz1dh-vmz1dh_is )
     171              :             else
     172              :             vintcza = vintcz( stars, vacuum, cell,  input, field, z, irec2, psq, &
     173              :                               vCoul%vac(:,:,:,ispin), &
     174            0 :                                 rhobar, sig1dh, vz1dh, alphm, vslope, sigma_disc, l_dfptvgen, l_corr, vmz1dh-vmz1dh_is, sigma_disc2 )
     175              :             end if 
     176       518985 :             if (l_dfptvgen) THEN 
     177            0 :               if (juphon%l_symVacLevel .AND. (irec2 == 1) ) vintcza = vintcza + constantShift
     178            0 :               vintcza = vintcza * gaussian
     179              :             end if 
     180       518985 :             af1(i) = real( vintcza )
     181       532435 :             bf1(i) = aimag( vintcza )
     182              :           end do
     183              :           !                z = (i_sm-1)*ani
     184              :           !                IF (z > 0.5) z = z - 1.0
     185              :           !                af1(i_sm) = af1(i_sm) + z * delta
     186              :           !                bf1(i_sm) = bf1(i_sm) + z * deltb
     187              :           !              ENDDO
     188              :           !            ENDIF
     189              : 
     190              : 
     191              :           !        --> 1-d fourier transform and store the coefficients in vTot%pw( ,1)
     192        13450 :           call cfft( af1, bf1, ivfft, ivfft, ivfft, -1 )
     193              :           !            delta = ivfft * delta * 2 / fpi ! * amat(3,3)**2 * ani
     194        13450 :           i = 0
     195       532472 :           do i3 = 0, ivfft - 1
     196       518985 :             k3 = i3
     197       518985 :             if ( k3 > floor( ivfft / 2. ) ) k3 = k3 - ivfft
     198       518985 :             i = i + 1
     199       532435 :             if ( ( k3 >= -stars%mx3 ) .and. ( k3 <= stars%mx3 ) ) then
     200       359440 :               irec3 = stars%ig(stars%kv2(1,irec2),stars%kv2(2,irec2),k3)
     201              :               !                 IF ( (irec2 == 1).AND.(i3 > 0) ) THEN                 ! smooth potential
     202              :               !                   corr = 2.0*mod(abs(k3),2) - 1.0
     203              :               !                   bf1(i) = bf1(i) + delta * corr / k3
     204              :               !                 ENDIF
     205              :               !       ----> only stars within g_max sphere (shz oct.97)
     206       359440 :               if ( irec3 /= 0 ) then
     207       226326 :                 xint = cmplx( af1(i), bf1(i) ) * ani
     208       226326 :                 nzst1 = stars%nstr(irec3) / stars%nstr2(irec2)
     209       226326 :                 vCoul%pw(irec3,1) = vCoul%pw(irec3,1) + xint / nzst1
     210              :               end if
     211              :             end if
     212              :           end do
     213              :         end do
     214           37 :         if (l_dfptvgen .AND. juphon%l_symVacLevel) vCoul%vac(:,1,:,ispin) = vCoul%vac(:,1,:,ispin) + constantShift
     215           37 :         sigma_disc = sigma_loc
     216              :       ! in case of a bulk system:
     217          304 :       else if ( .not. input%film ) then
     218          304 :         if ( vCoul%potdenType == POTDEN_TYPE_POTYUK ) then
     219              :           vCoul%pw(1:stars%ng3,ispin) = fpi_const * psq(1:stars%ng3) &
     220         3840 :             / ( stars%sk3(1:stars%ng3) ** 2 + input%preconditioning_param ** 2 )
     221              :           ! if( abs( real( psq(1) ) ) * cell%omtil < 0.01 ) vCoul%pw(1,ispin) = 0.0
     222              :           ! there is a better option now using qfix in mix
     223              :         else
     224          301 :           vCoul%pw(1,ispin) = cmplx(0.0,0.0)
     225          301 :           first_star = MERGE(2,1,stars%sk3(1)< 1E-9)
     226       608773 :           vCoul%pw(first_star:stars%ng3,ispin) = fpi_const * psq(first_star:stars%ng3) / stars%sk3(first_star:stars%ng3) ** 2
     227              :         end if
     228              :       end if
     229          341 :     call timestop("interstitial")
     230              :     end if ! fmpi%irank == 0
     231              : 
     232              :     ! MUFFIN-TIN POTENTIAL
     233          682 :     call timestart( "MT-spheres" )
     234              : #ifdef CPP_MPI
     235          682 :     CALL MPI_BARRIER(fmpi%mpi_comm,ierr) !should be totally useless, but needed anyway????
     236         2046 :     call MPI_BCAST( vcoul%pw, size(vcoul%pw), MPI_DOUBLE_COMPLEX, 0, fmpi%mpi_comm, ierr )
     237          682 :     CALL MPI_BARRIER(fmpi%mpi_comm,ierr) !should be totally useless, but ...
     238              : #endif
     239              : 
     240          682 :     IF (.NOT.l_dfptvgen) THEN
     241              :       call vmts( input, fmpi, stars, sphhar, atoms, sym, cell, juphon, dosf, vCoul%pw(:,ispin), &
     242          682 :                  den%mt(:,0:,:,ispin), vCoul%potdenType, vCoul%mt(:,0:,:,ispin) )
     243            0 :     ELSE IF (.NOT.l_2ndord) THEN
     244              :       ! For DFPT there is a) an imaginary part to the potential and b) a different treatment
     245              :       ! for the ionic 1/r (now 1/r^2) contribution.
     246              :       call vmts( input, fmpi, stars, sphhar, atoms, sym, cell, juphon, dosf, vCoul%pw(:,ispin), &
     247              :                  den%mt(:,0:,:,ispin), vCoul%potdenType, vCoul%mt(:,0:,:,ispin), &
     248            0 :                  dfptdenimag%mt(:,0:,:,ispin), dfptvCoulimag%mt(:,0:,:,ispin), iDtype, iDir )
     249              :     ELSE
     250              :       call vmts( input, fmpi, stars, sphhar, atoms, sym, cell, juphon, dosf, vCoul%pw(:,ispin), &
     251              :                  den%mt(:,0:,:,ispin), vCoul%potdenType, vCoul%mt(:,0:,:,ispin), &
     252            0 :                  dfptdenimag%mt(:,0:,:,ispin), dfptvCoulimag%mt(:,0:,:,ispin), iDtype, iDir, iDir2, mat2ord )
     253              :     END IF
     254          682 :     call timestop( "MT-spheres" )
     255              : 
     256          682 :     if( vCoul%potdenType == POTDEN_TYPE_POTYUK ) return
     257              : 
     258          676 :     if ( fmpi%irank == 0 ) then
     259          338 :       CHECK_CONTINUITY: if ( input%vchk ) then ! TODO: We could use this for DFPT as well if we
     260            4 :         call timestart( "checking" )           !       passed an optional to checkDOPAll and modded
     261              :         call checkDOPAll( input,  sphhar, stars, atoms, sym, vacuum,   & ! slightly.
     262            4 :                           cell, vCoul, ispin )
     263            4 :         call timestop( "checking" )
     264              :       end if CHECK_CONTINUITY
     265              : 
     266          338 :       CALCULATE_DENSITY_POTENTIAL_INTEGRAL: if ( present( results ) ) then
     267          337 :           call timestart( "den-pot integrals" )
     268              :           !     CALCULATE THE INTEGRAL OF n*Vcoulomb
     269          337 :           write(oUnit, fmt=8020 )
     270              : 8020      format (/,10x,'density-coulomb potential integrals',/)
     271              :           !       interstitial first
     272              :           !       convolute ufft and pot: F(G) = \sum_(G') U(G - G') V(G')
     273          337 :           call convol( stars, vCoul%pw_w(:,ispin), vCoul%pw(:,ispin))
     274          337 :           results%te_vcoul = 0.0
     275              :           call int_nv( ispin, stars, vacuum, atoms, sphhar, cell, sym, input,   &
     276          337 :                        vCoul, den, results%te_vcoul )
     277              : 
     278          337 :           write(oUnit, fmt=8030 ) results%te_vcoul
     279              : 8030      format (/,10x,'total density-coulomb potential integral :', t40,f20.10)
     280              : 
     281          337 :           call timestop( "den-pot integrals" )
     282              :       end if CALCULATE_DENSITY_POTENTIAL_INTEGRAL
     283              :     end if !irank==0
     284         2046 :   end subroutine vgen_coulomb
     285              : 
     286            0 :   subroutine make_mat_2nd(mat2ord)
     287              :      use m_constants
     288              :      complex, intent(out) :: mat2ord(5,3,3)
     289            0 :      mat2ord = cmplx(0.0,0.0)
     290              : 
     291            0 :      mat2ord(1,1,1) =  sqrt(3.0/2.0)
     292            0 :      mat2ord(1,1,2) =  sqrt(3.0/2.0)*ImagUnit
     293            0 :      mat2ord(1,2,1) =  sqrt(3.0/2.0)*ImagUnit
     294            0 :      mat2ord(1,2,2) = -sqrt(3.0/2.0)
     295              : 
     296            0 :      mat2ord(2,1,3) =  sqrt(3.0/2.0)
     297            0 :      mat2ord(2,2,3) =  sqrt(3.0/2.0)*ImagUnit   
     298            0 :      mat2ord(2,3,1) =  sqrt(3.0/2.0)
     299            0 :      mat2ord(2,3,2) =  sqrt(3.0/2.0)*ImagUnit  
     300              : 
     301            0 :      mat2ord(3,1,1) = -1.0! - 0.5 ! TODO: What the hell is this value???
     302            0 :      mat2ord(3,2,2) = -1.0! - 0.5 ! TODO: What the hell is this value???
     303            0 :      mat2ord(3,3,3) =  2.0! - 0.5 ! TODO: What the hell is this value???
     304              : 
     305            0 :      mat2ord(4,1,3) = -sqrt(3.0/2.0)
     306            0 :      mat2ord(4,2,3) =  sqrt(3.0/2.0)*ImagUnit   
     307            0 :      mat2ord(4,3,1) = -sqrt(3.0/2.0)
     308            0 :      mat2ord(4,3,2) =  sqrt(3.0/2.0)*ImagUnit  
     309              : 
     310            0 :      mat2ord(5,1,1) =  sqrt(3.0/2.0)
     311            0 :      mat2ord(5,1,2) = -sqrt(3.0/2.0)*ImagUnit
     312            0 :      mat2ord(5,2,1) = -sqrt(3.0/2.0)*ImagUnit
     313            0 :      mat2ord(5,2,2) = -sqrt(3.0/2.0)
     314              : 
     315            0 :      mat2ord = sqrt(4.0*pi_const/5.0) * mat2ord
     316            0 :   end subroutine
     317              : 
     318              : end module m_vgen_coulomb
        

Generated by: LCOV version 2.0-1