LCOV - code coverage report
Current view: top level - vgen - vgen_coulomb.F90 (source / functions) Hit Total Coverage
Test: FLEUR test coverage Lines: 86 118 72.9 %
Date: 2024-04-19 04:21:58 Functions: 1 2 50.0 %

          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         696 :   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
      74             :     complex                                      :: mat2ord(5,3,3), sigma_loc(2), sigma_loc2(2)
      75         696 :     complex, allocatable                         :: alphm(:,:), psq(:)
      76         696 :     real,    allocatable                         :: af1(:), bf1(:)
      77             :     LOGICAL :: l_dfptvgen ! If this is true, we handle things differently!
      78             :     LOGICAL :: l_2ndord, l_corr
      79             : 
      80             : #ifdef CPP_MPI
      81             :     integer:: ierr
      82             : #endif
      83             : 
      84         696 :     l_dfptvgen = PRESENT(stars2)
      85         696 :     l_2ndord = PRESENT(iDir2)
      86        4224 :     l_corr = ALL(ABS(den%vac)<1e-12)
      87         696 :     vmz1dh_is = cmplx(0.0,0.0)
      88         696 :     sigma_loc = sigma_disc
      89        2088 :     sigma_loc2 = MERGE(sigma_disc,cmplx(0.0,0.0),PRESENT(sigma_disc2))
      90             : 
      91         696 :     vintcza = cmplx(0.0,0.0)
      92         696 :     sig1dh = cmplx(0.0,0.0)
      93         696 :     vz1dh = cmplx(0.0,0.0)
      94         696 :     vmz1dh = cmplx(0.0,0.0)
      95         696 :     vslope = cmplx(0.0,0.0)
      96             : 
      97         696 :     allocate ( alphm(stars%ng2,2), af1(3*stars%mx3), bf1(3*stars%mx3), psq(stars%ng3)  )
      98         696 :     vCoul%iter = den%iter
      99             : 
     100             :     ! PSEUDO-CHARGE DENSITY COEFFICIENTS
     101         696 :     call timestart( "psqpw" )
     102         696 :     if (.not.l_dfptvgen) then
     103             :         call psqpw( fmpi, atoms, sphhar, stars, vacuum,  cell, input, sym,   &
     104         696 :             & juphon, den, ispin, .false., vCoul%potdenType, psq, sigma_loc )
     105           0 :     else if (.not.l_2ndord) then
     106             :         ! If we do DFPT, the MT density perturbation has an imaginary part that needs to be explicitly carried
     107             :         ! as another variable dfptdenimag%mt and results in the same component for the Coulomb potential later on.
     108             :         ! Also, the ionic qlm behave differently.
     109             :         call psqpw( fmpi, atoms, sphhar, stars, vacuum,  cell, input, sym,   &
     110             :             & juphon, den, ispin, .false., vCoul%potdenType, psq, sigma_loc,&
     111           0 :             & dfptdenimag%mt(:,:,:,ispin), stars2, iDtype, iDir, dfptden0%mt(:,:,:,ispin), dfptden0%pw(:,ispin) )
     112             :     else
     113           0 :         call make_mat_2nd(mat2ord)
     114             :         call psqpw( fmpi, atoms, sphhar, stars, vacuum,  cell, input, sym,   &
     115             :             & juphon, den, ispin, .false., vCoul%potdenType, psq, sigma_loc,&
     116           0 :             & dfptdenimag%mt(:,:,:,ispin), stars2, iDtype, iDir, dfptden0%mt(:,:,:,ispin), dfptden0%pw(:,ispin), iDir2, mat2ord )
     117             :     end if
     118         696 :     call timestop( "psqpw" )
     119             : 
     120             :     ! VACUUM POTENTIAL
     121         696 :     if ( fmpi%irank == 0 ) then
     122         348 :       if ( input%film ) then
     123             :         !     ----> potential in the  vacuum  region
     124          44 :         call timestart( "Vacuum" )
     125         176 :         if ((.not.l_dfptvgen).or.norm2(stars%center)<1e-8) then
     126             :           ! If we do DPFT AND q/=0, there is no G_||+q_||=0 part! So all components are
     127             :           ! handled by the G_||/=0 parts in vvacis/vvacxy, that are told to explicitly
     128             :           ! start at star 1 instead of 2 for this!
     129          44 :           if (.not.l_2ndord) then
     130             :             !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 )
     131          44 :             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 )
     132             :           else
     133             :             !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 )
     134           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 )
     135             :           end if
     136             :         end if
     137          44 :         call vvacis( stars, vacuum, cell, psq, input, field, vCoul%vac(:vacuum%nmzxyd,:,:,ispin), l_dfptvgen, l_corr )
     138          44 :         call vvacxy( stars, vacuum, cell, sym, input, field, den%vac(:vacuum%nmzxyd,:,:,ispin), vCoul%vac(:vacuum%nmzxyd,:,:,ispin), alphm, l_dfptvgen )
     139          44 :         call timestop( "Vacuum" )
     140             :       end if
     141             : 
     142             :       ! INTERSTITIAL POTENTIAL
     143         348 :       call timestart( "interstitial" )
     144         348 :       write(oUnit, fmt=8010 )
     145             : 8010  format (/,5x,'coulomb potential in the interstitial region:')
     146             :       ! in case of a film:
     147         348 :       if ( input%film ) then
     148             :         ! create v(z) for each 2-d reciprocal vector
     149          44 :         ivfft = 3 * stars%mx3
     150          44 :         ani = 1.0 / real( ivfft )
     151       17421 :         do irec2 = 1, stars%ng2
     152             :           ! If we do DFPT, we want to fix the second vacuum at infinity to 0. This is WIP,
     153             :           ! as to how we want to do it eventually. Here, we calculate the necessary offset.
     154             :           !IF (l_dfptvgen.AND.irec2 == 1) vmz1dh_is = vintcz( stars, vacuum, cell,  input, field, -cell%z1+1e-15, irec2, psq, &
     155             :           !                    vCoul%vac(:,:,:,ispin), &
     156             :           !                    rhobar, sig1dh, vz1dh, alphm, vslope, .TRUE., CMPLX(0.0,0.0) )
     157       17377 :           i = 0
     158      665953 :           do i3 = 0, ivfft - 1
     159      648576 :             i = i + 1
     160      648576 :             z = cell%amat(3,3) * i3 * ani
     161      648576 :             if ( z > cell%amat(3,3) / 2. ) z = z - cell%amat(3,3)
     162      648576 :             if (.not.l_2ndord) then
     163             :               vintcza = vintcz( stars, vacuum, cell,  input, field, z, irec2, psq, &
     164             :                                 vCoul%vac(:,:,:,ispin), &
     165      648576 :                                 rhobar, sig1dh, vz1dh, alphm, vslope, sigma_disc, l_dfptvgen, l_corr, vmz1dh-vmz1dh_is )
     166             :             else
     167             :             vintcza = vintcz( stars, vacuum, cell,  input, field, z, irec2, psq, &
     168             :                               vCoul%vac(:,:,:,ispin), &
     169           0 :                                 rhobar, sig1dh, vz1dh, alphm, vslope, sigma_disc, l_dfptvgen, l_corr, vmz1dh-vmz1dh_is, sigma_disc2 )
     170             :             end if
     171      648576 :             af1(i) = real( vintcza )
     172      665953 :             bf1(i) = aimag( vintcza )
     173             :           end do
     174             :           !                z = (i_sm-1)*ani
     175             :           !                IF (z > 0.5) z = z - 1.0
     176             :           !                af1(i_sm) = af1(i_sm) + z * delta
     177             :           !                bf1(i_sm) = bf1(i_sm) + z * deltb
     178             :           !              ENDDO
     179             :           !            ENDIF
     180             : 
     181             : 
     182             :           !        --> 1-d fourier transform and store the coefficients in vTot%pw( ,1)
     183       17377 :           call cfft( af1, bf1, ivfft, ivfft, ivfft, -1 )
     184             :           !            delta = ivfft * delta * 2 / fpi ! * amat(3,3)**2 * ani
     185       17377 :           i = 0
     186      665997 :           do i3 = 0, ivfft - 1
     187      648576 :             k3 = i3
     188      648576 :             if ( k3 > floor( ivfft / 2. ) ) k3 = k3 - ivfft
     189      648576 :             i = i + 1
     190      665953 :             if ( ( k3 >= -stars%mx3 ) .and. ( k3 <= stars%mx3 ) ) then
     191      449761 :               irec3 = stars%ig(stars%kv2(1,irec2),stars%kv2(2,irec2),k3)
     192             :               !                 IF ( (irec2 == 1).AND.(i3 > 0) ) THEN                 ! smooth potential
     193             :               !                   corr = 2.0*mod(abs(k3),2) - 1.0
     194             :               !                   bf1(i) = bf1(i) + delta * corr / k3
     195             :               !                 ENDIF
     196             :               !       ----> only stars within g_max sphere (shz oct.97)
     197      449761 :               if ( irec3 /= 0 ) then
     198      282753 :                 xint = cmplx( af1(i), bf1(i) ) * ani
     199      282753 :                 nzst1 = stars%nstr(irec3) / stars%nstr2(irec2)
     200      282753 :                 vCoul%pw(irec3,1) = vCoul%pw(irec3,1) + xint / nzst1
     201             :               end if
     202             :             end if
     203             :           end do
     204             :         end do
     205          44 :         sigma_disc = sigma_loc
     206             :       ! in case of a bulk system:
     207         304 :       else if ( .not. input%film ) then
     208         304 :         if ( vCoul%potdenType == POTDEN_TYPE_POTYUK ) then
     209             :           vCoul%pw(1:stars%ng3,ispin) = fpi_const * psq(1:stars%ng3) &
     210        3840 :             / ( stars%sk3(1:stars%ng3) ** 2 + input%preconditioning_param ** 2 )
     211             :           ! if( abs( real( psq(1) ) ) * cell%omtil < 0.01 ) vCoul%pw(1,ispin) = 0.0
     212             :           ! there is a better option now using qfix in mix
     213             :         else
     214         301 :           vCoul%pw(1,ispin) = cmplx(0.0,0.0)
     215         301 :           first_star = MERGE(2,1,stars%sk3(1)< 1E-9)
     216      608773 :           vCoul%pw(first_star:stars%ng3,ispin) = fpi_const * psq(first_star:stars%ng3) / stars%sk3(first_star:stars%ng3) ** 2
     217             :         end if
     218             :       end if
     219         348 :     call timestop("interstitial")
     220             :     end if ! fmpi%irank == 0
     221             : 
     222             :     ! MUFFIN-TIN POTENTIAL
     223         696 :     call timestart( "MT-spheres" )
     224             : #ifdef CPP_MPI
     225         696 :     CALL MPI_BARRIER(fmpi%mpi_comm,ierr) !should be totally useless, but needed anyway????
     226        2088 :     call MPI_BCAST( vcoul%pw, size(vcoul%pw), MPI_DOUBLE_COMPLEX, 0, fmpi%mpi_comm, ierr )
     227         696 :     CALL MPI_BARRIER(fmpi%mpi_comm,ierr) !should be totally useless, but ...
     228             : #endif
     229             : 
     230         696 :     IF (.NOT.l_dfptvgen) THEN
     231             :       call vmts( input, fmpi, stars, sphhar, atoms, sym, cell,   dosf, vCoul%pw(:,ispin), &
     232         696 :                  den%mt(:,0:,:,ispin), vCoul%potdenType, vCoul%mt(:,0:,:,ispin) )
     233           0 :     ELSE IF (.NOT.l_2ndord) THEN
     234             :       ! For DFPT there is a) an imaginary part to the potential and b) a different treatment
     235             :       ! for the ionic 1/r (now 1/r^2) contribution.
     236             :       call vmts( input, fmpi, stars, sphhar, atoms, sym, cell,   dosf, vCoul%pw(:,ispin), &
     237             :                  den%mt(:,0:,:,ispin), vCoul%potdenType, vCoul%mt(:,0:,:,ispin), &
     238           0 :                  dfptdenimag%mt(:,0:,:,ispin), dfptvCoulimag%mt(:,0:,:,ispin), iDtype, iDir )
     239             :     ELSE
     240             :       call vmts( input, fmpi, stars, sphhar, atoms, sym, cell,   dosf, vCoul%pw(:,ispin), &
     241             :                  den%mt(:,0:,:,ispin), vCoul%potdenType, vCoul%mt(:,0:,:,ispin), &
     242           0 :                  dfptdenimag%mt(:,0:,:,ispin), dfptvCoulimag%mt(:,0:,:,ispin), iDtype, iDir, iDir2, mat2ord )
     243             :     END IF
     244         696 :     call timestop( "MT-spheres" )
     245             : 
     246         696 :     if( vCoul%potdenType == POTDEN_TYPE_POTYUK ) return
     247             : 
     248         690 :     if ( fmpi%irank == 0 ) then
     249         345 :       CHECK_CONTINUITY: if ( input%vchk ) then ! TODO: We could use this for DFPT as well if we
     250           4 :         call timestart( "checking" )           !       passed an optional to checkDOPAll and modded
     251             :         call checkDOPAll( input,  sphhar, stars, atoms, sym, vacuum,   & ! slightly.
     252           4 :                           cell, vCoul, ispin )
     253           4 :         call timestop( "checking" )
     254             :       end if CHECK_CONTINUITY
     255             : 
     256         345 :       CALCULATE_DENSITY_POTENTIAL_INTEGRAL: if ( present( results ) ) then
     257         344 :           call timestart( "den-pot integrals" )
     258             :           !     CALCULATE THE INTEGRAL OF n*Vcoulomb
     259         344 :           write(oUnit, fmt=8020 )
     260             : 8020      format (/,10x,'density-coulomb potential integrals',/)
     261             :           !       interstitial first
     262             :           !       convolute ufft and pot: F(G) = \sum_(G') U(G - G') V(G')
     263         344 :           call convol( stars, vCoul%pw_w(:,ispin), vCoul%pw(:,ispin))
     264         344 :           results%te_vcoul = 0.0
     265             :           call int_nv( ispin, stars, vacuum, atoms, sphhar, cell, sym, input,   &
     266         344 :                        vCoul, den, results%te_vcoul )
     267             : 
     268         344 :           write(oUnit, fmt=8030 ) results%te_vcoul
     269             : 8030      format (/,10x,'total density-coulomb potential integral :', t40,f20.10)
     270             : 
     271         344 :           call timestop( "den-pot integrals" )
     272             :       end if CALCULATE_DENSITY_POTENTIAL_INTEGRAL
     273             :     end if !irank==0
     274        2088 :   end subroutine vgen_coulomb
     275             : 
     276           0 :   subroutine make_mat_2nd(mat2ord)
     277             :      use m_constants
     278             :      complex, intent(out) :: mat2ord(5,3,3)
     279           0 :      mat2ord = cmplx(0.0,0.0)
     280             : 
     281           0 :      mat2ord(1,1,1) =  sqrt(3.0/2.0)
     282           0 :      mat2ord(1,1,2) =  sqrt(3.0/2.0)*ImagUnit
     283           0 :      mat2ord(1,2,1) =  sqrt(3.0/2.0)*ImagUnit
     284           0 :      mat2ord(1,2,2) = -sqrt(3.0/2.0)
     285             : 
     286           0 :      mat2ord(2,1,3) =  sqrt(3.0/2.0)
     287           0 :      mat2ord(2,2,3) =  sqrt(3.0/2.0)*ImagUnit   
     288           0 :      mat2ord(2,3,1) =  sqrt(3.0/2.0)
     289           0 :      mat2ord(2,3,2) =  sqrt(3.0/2.0)*ImagUnit  
     290             : 
     291           0 :      mat2ord(3,1,1) = -1.0! - 0.5 ! TODO: What the hell is this value???
     292           0 :      mat2ord(3,2,2) = -1.0! - 0.5 ! TODO: What the hell is this value???
     293           0 :      mat2ord(3,3,3) =  2.0! - 0.5 ! TODO: What the hell is this value???
     294             : 
     295           0 :      mat2ord(4,1,3) = -sqrt(3.0/2.0)
     296           0 :      mat2ord(4,2,3) =  sqrt(3.0/2.0)*ImagUnit   
     297           0 :      mat2ord(4,3,1) = -sqrt(3.0/2.0)
     298           0 :      mat2ord(4,3,2) =  sqrt(3.0/2.0)*ImagUnit  
     299             : 
     300           0 :      mat2ord(5,1,1) =  sqrt(3.0/2.0)
     301           0 :      mat2ord(5,1,2) = -sqrt(3.0/2.0)*ImagUnit
     302           0 :      mat2ord(5,2,1) = -sqrt(3.0/2.0)*ImagUnit
     303           0 :      mat2ord(5,2,2) = -sqrt(3.0/2.0)
     304             : 
     305           0 :      mat2ord = sqrt(4.0*pi_const/5.0) * mat2ord
     306           0 :   end subroutine
     307             : 
     308             : end module m_vgen_coulomb

Generated by: LCOV version 1.14