LCOV - code coverage report
Current view: top level - tetra - tetrahedronInit.f90 (source / functions) Hit Total Coverage
Test: FLEUR test coverage Lines: 85 93 91.4 %
Date: 2024-05-15 04:28:08 Functions: 3 3 100.0 %

          Line data    Source code
       1             : MODULE m_tetrahedronInit
       2             : 
       3             :    !------------------------------------------------------------------------------------
       4             :    !This module provides the weights for the linear tetrahedron/triangular method
       5             :    !for Brillouin-zone integration with the step function as the weight
       6             :    !
       7             :    !This module should be used by calling the interface tetrahedronInit
       8             :    !
       9             :    !Structure:
      10             :    !     tetrahedronInit:
      11             :    !        getWeightKpoints:    gives weight at one (fermi) energy for all kpoints
      12             :    !        getWeightEnergyMesh: gives weight on an energy grid for one kpoint.
      13             :    !                             By providing the dos switch as .TRUE. the weights are
      14             :    !                             numerically differentiated for use for DOS calculations
      15             :    !
      16             :    !These subroutines all call getWeightSingleBand which handles the actual calculation
      17             :    !of weights. These differ in the order of the loops and the arguments provided.
      18             :    !------------------------------------------------------------------------------------
      19             : 
      20             :    USE m_types_kpts
      21             :    USE m_types_input
      22             :    USE m_juDFT
      23             : 
      24             :    IMPLICIT NONE
      25             : 
      26             :    PRIVATE
      27             :    PUBLIC   :: tetrahedronInit
      28             : 
      29             :    INTERFACE tetrahedronInit
      30             :       PROCEDURE getWeightKpoints, getWeightEnergyMesh
      31             :    END INTERFACE
      32             : 
      33             :    REAL, PARAMETER :: weightCutoff=1e-14
      34             :    real, parameter :: tol_degeneracy=1e-9
      35             : 
      36             :    CONTAINS
      37             : 
      38        1794 :    SUBROUTINE getWeightKpoints(kpts,input,eig,neig,efermi,weightSum,weights)
      39             : 
      40             :       TYPE(t_kpts),  INTENT(IN)    :: kpts
      41             :       TYPE(t_input), INTENT(IN)    :: input
      42             :       REAL,          INTENT(IN)    :: eig(:,:)
      43             :       INTEGER,       INTENT(IN)    :: neig
      44             :       REAL,          INTENT(IN)    :: efermi
      45             :       REAL, OPTIONAL,INTENT(INOUT) :: weightSum
      46             :       REAL, OPTIONAL,INTENT(INOUT) :: weights(:,:)
      47             : 
      48             :       INTEGER :: ikpt,ncorn,itet,icorn,iband,num_degenerate_states,last_band
      49        1794 :       REAL    :: w(1),etetra(SIZE(kpts%ntetra,1)),vol(kpts%ntet)
      50             :       logical :: l_weights_pres, l_weightsum_pres
      51             : 
      52        1794 :       IF(.NOT.PRESENT(weightSum).AND..NOT.PRESENT(weights)) THEN
      53             :          CALL juDFT_error("No output variable provided (either weightSum or weights)",&
      54           0 :                            calledby="getWeightKpoints")
      55             :       ENDIF
      56             : 
      57        1794 :       l_weights_pres = PRESENT(weights)
      58        1794 :       l_weightsum_pres = PRESENT(weightSum)
      59             :       !Tetrahedra or Triangles?
      60        1794 :       ncorn = MERGE(3,4,input%film)
      61             : 
      62       37604 :       IF(PRESENT(weights)) weights = 0.0
      63        1794 :       IF(PRESENT(weightSum)) weightSum = 0.0
      64             : 
      65      503334 :       vol = kpts%voltet(:)/kpts%ntet
      66             : 
      67             :       !More efficient to just loop through all tetrahedra
      68             :       !$OMP parallel do default(none) &
      69             :       !$OMP shared(neig,ncorn,vol,l_weights_pres,l_weightsum_pres) &
      70             :       !$OMP shared(kpts,input,eig,weights,efermi) &
      71             :       !$OMP private(itet,ikpt,icorn,iband,etetra,w) &
      72        1794 :       !$OMP reduction(+:weightSum) collapse(3)
      73             :       DO itet = 1, kpts%ntet
      74             :          DO icorn = 1, ncorn
      75             :             DO iband = 1, neig
      76             : 
      77             :                ikpt = kpts%ntetra(icorn,itet)
      78             :                etetra = eig(iband,kpts%ntetra(:,itet))
      79             : 
      80             :                IF( ALL(etetra>efermi + 1E-8) .AND. .NOT.input%l_bloechl ) CYCLE
      81             : 
      82             :                w  = getWeightSingleBand([efermi],etetra,icorn,vol(itet),input%film,input%l_bloechl)
      83             : 
      84             :                IF(l_weightsum_pres) weightSum = weightSum + w(1)
      85             : 
      86             :                IF(l_weights_pres) THEN
      87             :                   !$OMP critical
      88             :                   weights(iband,ikpt) = weights(iband,ikpt) + w(1)
      89             :                   !$OMP end critical
      90             :                ENDIF
      91             :             ENDDO
      92             :          ENDDO
      93             :       ENDDO
      94             :       !$OMP end parallel do
      95             : 
      96        1794 :       if (l_weights_pres) then
      97             :          !find degenerate states
      98        2110 :          do ikpt=1,kpts%nkpt
      99             :             iband = 1
     100       31258 :             do while(iband<neig)
     101             :                num_degenerate_states=1
     102       30116 :                do while (abs(eig(iband,ikpt)-eig(iband+num_degenerate_states,ikpt))<tol_degeneracy)
     103         986 :                   num_degenerate_states=num_degenerate_states+1
     104       30116 :                   if (iband+num_degenerate_states>neig) exit
     105             :                enddo
     106             : 
     107       29148 :                if (num_degenerate_states>1) THEN
     108         850 :                   last_band=iband+num_degenerate_states-1
     109             :                   !Make sure all weights are equal
     110        4522 :                   weights(iband:last_band,ikpt)=sum(weights(iband:last_band,ikpt))/num_degenerate_states
     111             :                   iband=last_band
     112             :                endif
     113       29148 :                iband=iband+1
     114             :             enddo
     115             :          enddo
     116             :       endif
     117             : 
     118        1794 :    END SUBROUTINE getWeightKpoints
     119             : 
     120         144 :    SUBROUTINE getWeightEnergyMesh(kpts,input,ikpt,eig,neig,eMesh,weights,resWeights,bounds,dos)
     121             : 
     122             :       USE m_differentiate
     123             : 
     124             :       TYPE(t_kpts),     INTENT(IN)    :: kpts
     125             :       TYPE(t_input),    INTENT(IN)    :: input
     126             :       REAL,             INTENT(IN)    :: eig(:,:)
     127             :       REAL,             INTENT(INOUT) :: weights(:,:)
     128             :       INTEGER,OPTIONAL, INTENT(INOUT) :: bounds(:,:)
     129             :       REAL, OPTIONAL,   INTENT(INOUT) :: resWeights(:,:)
     130             : 
     131             :       INTEGER,          INTENT(IN)  :: neig
     132             :       INTEGER,          INTENT(IN)  :: ikpt
     133             :       REAL,             INTENT(IN)  :: eMesh(:)
     134             :       LOGICAL,OPTIONAL, INTENT(IN)  :: dos
     135             : 
     136             :       INTEGER :: itet,iband,ncorn,ie,icorn,ntet,num_degenerate_states, last_band,i
     137             :       LOGICAL :: l_dos, l_bounds_pres, l_resWeights_pres
     138         144 :       REAL    :: etetra(SIZE(kpts%ntetra,1),neig,SIZE(kpts%tetraList,1)),del,vol
     139         144 :       REAL, ALLOCATABLE :: dos_weights(:)
     140             :       !Temporary Arrays to include end points
     141             :       !to avoid numerical trouble with differentiation
     142         144 :       REAL, ALLOCATABLE :: calc_weights(:,:)
     143         144 :       REAL, ALLOCATABLE :: calc_weights_thread(:,:),resWeights_thread(:,:)
     144         144 :       REAL, ALLOCATABLE :: calc_eMesh(:)
     145         144 :       real, allocatable :: mean_weight(:)
     146             : 
     147             :       !Extract the right eigenvalues
     148         144 :       IF(kpts%tetraList(1,ikpt)==0) CALL juDFT_error("No tetrahedrons in tetraList", calledby="tetrahedronInit")
     149             :       ntet = 1
     150             :       do
     151        3936 :          itet = kpts%tetraList(ntet,ikpt)
     152             : 
     153      178486 :          do iband = 1, neig
     154     1723036 :             etetra(:,iband,ntet) = eig(iband,kpts%ntetra(:,itet))
     155             :          enddo
     156        4080 :          if(ntet < SIZE(kpts%tetraList,1)) THEN
     157        3936 :             if(kpts%tetraList(ntet+1,ikpt)>0) THEN
     158             :                ntet = ntet + 1
     159             :             else
     160             :                exit
     161             :             endif
     162             :          else
     163             :             exit
     164             :          endif
     165             :       enddo
     166             : 
     167         144 :       l_dos = PRESENT(dos)
     168         144 :       IF(PRESENT(dos))THEN
     169         144 :          l_dos = dos.AND.SIZE(eMesh)>1
     170             :       ENDIF
     171             : 
     172         144 :       IF(PRESENT(resWeights)) resWeights = 0.0
     173             : 
     174         144 :       IF(l_dos) THEN
     175    34540152 :          ALLOCATE(calc_weights(SIZE(eMesh)+2,neig),source=0.0)
     176      713520 :          ALLOCATE(calc_eMesh(SIZE(eMesh)+2),source=0.0)
     177      713520 :          ALLOCATE(mean_weight(SIZE(eMesh)+2),source=0.0)
     178         144 :          del = eMesh(2)-eMesh(1)
     179     1426320 :          calc_eMesh = [eMesh(1)-del,eMesh(:),eMesh(SIZE(eMesh))+del]
     180             :       ELSE
     181           0 :          ALLOCATE(calc_weights(SIZE(eMesh),neig),source=0.0)
     182           0 :          ALLOCATE(calc_eMesh(SIZE(eMesh)),source=0.0)
     183           0 :          ALLOCATE(mean_weight(SIZE(eMesh)),source=0.0)
     184           0 :          calc_eMesh = eMesh
     185             :       ENDIF
     186             : 
     187         144 :       l_resWeights_pres = PRESENT(resWeights)
     188             :       !$OMP parallel default(none)&
     189             :       !$OMP shared(neig,ntet,l_resWeights_pres,kpts,input,ikpt,resWeights,calc_weights) &
     190             :       !$OMP shared(etetra,calc_eMesh,eMesh) &
     191         144 :       !$OMP private(itet,iband,vol,icorn,resWeights_thread,calc_weights_thread)
     192             :       IF(l_resWeights_pres) ALLOCATE(resWeights_thread(SIZE(resWeights,1),SIZE(resWeights,2)),source = 0.0)
     193             :       ALLOCATE(calc_weights_thread(SIZE(calc_weights,1),SIZE(calc_weights,2)),source = 0.0)
     194             :       !$OMP do collapse(3)
     195             :       DO itet = 1, ntet
     196             :          DO iband = 1, neig
     197             :             DO icorn = 1, SIZE(kpts%ntetra,1)
     198             : 
     199             :                vol = kpts%voltet(kpts%tetraList(itet,ikpt))/kpts%ntet
     200             :                IF(kpts%ntetra(icorn,kpts%tetraList(itet,ikpt)).NE.ikpt) CYCLE
     201             : 
     202             :                IF(l_resWeights_pres) THEN
     203             :                   resWeights_thread(:,iband) = resWeights_thread(:,iband) &
     204             :                                               + getWeightSingleBand(eMesh,etetra(:,iband,itet),icorn,vol,&
     205             :                                                                     input%film,input%l_bloechl,l_res=.TRUE.)
     206             :                ENDIF
     207             : 
     208             :                IF( ALL(etetra(:,iband,itet)>MAXVAL(calc_eMesh) + 1E-8) .AND. .NOT.input%l_bloechl ) CYCLE
     209             : 
     210             :                calc_weights_thread(:,iband) = calc_weights_thread(:,iband) &
     211             :                                              + getWeightSingleBand(calc_eMesh,etetra(:,iband,itet),icorn,vol,&
     212             :                                                                    input%film,input%l_bloechl)
     213             :             ENDDO
     214             :          ENDDO
     215             :       ENDDO
     216             :       !$OMP end do
     217             :       !$OMP critical
     218             :       IF(l_resWeights_pres) resWeights = resWeights + resWeights_thread
     219             :       calc_weights = calc_weights + calc_weights_thread
     220             :       !$OMP end critical
     221             :       DEALLOCATE(calc_weights_thread)
     222             :       IF(l_resWeights_pres) DEALLOCATE(resWeights_thread)
     223             :       !$OMP end parallel
     224             : 
     225             :       !find degenerate states
     226         144 :       iband = 1
     227        6604 :       do while(iband<neig)
     228             :          num_degenerate_states=1
     229        7448 :          do while (abs(eig(iband,ikpt)-eig(iband+num_degenerate_states,ikpt))<tol_degeneracy)
     230         992 :             num_degenerate_states=num_degenerate_states+1
     231        7448 :             if (iband+num_degenerate_states>neig) exit
     232             :          enddo
     233             : 
     234        6460 :          if (num_degenerate_states>1) THEN
     235         854 :             last_band=iband+num_degenerate_states-1
     236             :             !Make sure all weights are equal
     237    13841908 :             mean_weight = sum(calc_weights(:,iband:last_band), dim=2)/num_degenerate_states
     238        2700 :             do i = iband, last_band
     239     9477992 :                calc_weights(:,i) = mean_weight
     240             :             enddo
     241             :             iband=last_band
     242             :          endif
     243        6604 :          iband=iband+1
     244             :       enddo
     245             : 
     246    34524536 :       weights = 0.0
     247         144 :       l_bounds_pres = PRESENT(bounds)
     248             :       !-------------------------------------
     249             :       ! PostProcess weights
     250             :       !-------------------------------------
     251             :       !$OMP parallel default(none) &
     252             :       !$OMP shared(neig,l_dos,del,eMesh) &
     253             :       !$OMP shared(calc_weights,weights,bounds,l_bounds_pres,l_resWeights_pres) &
     254         144 :       !$OMP private(iband,dos_weights,ie)
     255             :       IF(l_dos) ALLOCATE(dos_weights(SIZE(eMesh)+2),source=0.0)
     256             :       !$OMP do schedule(dynamic,1)
     257             :       DO iband = 1, neig
     258             :          !---------------------------------------------------
     259             :          ! Weights for DOS -> differentiate with respect to E
     260             :          !---------------------------------------------------
     261             :          IF(l_dos) THEN
     262             :             CALL diff3(calc_weights(:,iband),del,dos_weights)
     263             :             weights(1:SIZE(eMesh),iband) = dos_weights(2:SIZE(eMesh)+1)
     264             :          ELSE
     265             :             weights(:,:neig) = calc_weights
     266             :          ENDIF
     267             :          !--------------------------------------------------------------
     268             :          ! Find the range where the weights are bigger than weightCutoff
     269             :          !--------------------------------------------------------------
     270             :          IF(l_bounds_pres.AND..NOT.l_resWeights_pres) THEN
     271             :             !--------------------
     272             :             ! Lower bound
     273             :             !--------------------
     274             :             ie = 1
     275             :             DO
     276             :                IF(ABS(weights(ie,iband)).GT.weightCutoff) THEN
     277             :                   bounds(iband,1) = ie
     278             :                   EXIT
     279             :                ELSE
     280             :                   weights(ie,iband) = 0.0
     281             :                   ie = ie + 1
     282             :                   IF(ie.EQ.SIZE(eMesh)) THEN
     283             :                      bounds(iband,1) = SIZE(eMesh)
     284             :                      EXIT
     285             :                   ENDIF
     286             :                ENDIF
     287             :             ENDDO
     288             :             !--------------------
     289             :             ! Upper bound
     290             :             !--------------------
     291             :             ie = SIZE(eMesh)
     292             :             DO
     293             :                IF(ABS(weights(ie,iband)).GT.weightCutoff) THEN
     294             :                   bounds(iband,2) = ie
     295             :                   EXIT
     296             :                ELSE
     297             :                   weights(ie,iband) = 0.0
     298             :                   ie = ie - 1
     299             :                   IF(ie.EQ.0) THEN
     300             :                      bounds(iband,2) = 1
     301             :                      EXIT
     302             :                   ENDIF
     303             :                ENDIF
     304             :             ENDDO
     305             :             !For safety
     306             :             IF(bounds(iband,1).GT.bounds(iband,2)) THEN
     307             :                bounds(iband,1) = 1
     308             :                bounds(iband,2) = 1
     309             :             ENDIF
     310             :          ELSE IF(l_bounds_pres) THEN
     311             :             bounds(iband,1) = 1
     312             :             bounds(iband,2) = SIZE(eMesh)
     313             :          ENDIF
     314             :       ENDDO
     315             :       !$OMP end do
     316             :       IF(l_dos) DEALLOCATE(dos_weights)
     317             :       !$OMP end parallel
     318             : 
     319    34524536 :       IF(ANY(weights(:,:neig)<0.0).AND..NOT.input%l_bloechl) THEN
     320           0 :          CALL juDFT_error("TetraWeight error: Unexpected negative weight", calledby="getWeightEnergyMesh")
     321             :       ENDIF
     322             : 
     323         144 :    END SUBROUTINE getWeightEnergyMesh
     324             : 
     325             : 
     326    25068210 :    PURE FUNCTION getWeightSingleBand(eMesh,etetra,icorn,vol,film,l_bloechl,l_res) Result(weight)
     327             : 
     328             :       !--------------------------------------------------------------
     329             :       ! This is the core routine calculating the integration
     330             :       ! weight for one kpoint in one tetrahedron for one band index
     331             :       ! for the provided energy points
     332             :       ! All other routines wrap this procedure so that it is most
     333             :       ! efficient in all cases
     334             :       !--------------------------------------------------------------
     335             : 
     336             :       USE m_tetsrt
     337             :       USE m_tetraWeight
     338             :       USE m_resWeight
     339             :       USE m_bloechl
     340             : 
     341             :       REAL,             INTENT(IN)     :: eMesh(:)    !Energy points, where the weights are calculated
     342             :       REAL,             INTENT(IN)     :: etetra(:)   !Eigenvalues at the corners of the tetrahedron
     343             :       INTEGER,          INTENT(IN)     :: icorn       !Current k-point index (We calculate the weights for this corner)
     344             :       REAL,             INTENT(IN)     :: vol         !Volume of the tetrahedron
     345             :       LOGICAL,          INTENT(IN)     :: film        !Switch controls wether tetrahedron/triangular method is used
     346             :       LOGICAL,          INTENT(IN)     :: l_bloechl   !Controls bloechl corrections
     347             :       LOGICAL, OPTIONAL,INTENT(IN)     :: l_res
     348             : 
     349             :       REAL    :: weight(SIZE(eMesh))
     350    25068210 :       INTEGER :: i,ie,nstart,nend,ind(SIZE(etetra)),icornSorted
     351             :       REAL    :: eb,et,del
     352             :       LOGICAL :: l_calcres
     353             : 
     354             : 
     355             :       !Sort the eigenvalues at the corners (ascending order in ind)
     356    25068210 :       ind = tetsrt(etetra)
     357             : 
     358             :       !Find out where the corner went
     359   125281488 :       DO i = 1, SIZE(ind)
     360   125281488 :          IF(ind(i)==icorn) icornSorted = i
     361             :       ENDDO
     362             : 
     363    25068210 :       l_calcres = .FALSE.
     364    25068210 :       IF(PRESENT(l_res)) l_calcres = l_res
     365             : 
     366           0 :       IF(l_calcres) THEN
     367           0 :          weight = resWeight(eMesh,etetra(ind),icornSorted,vol,film)
     368             :       ELSE
     369             :          !Find the range in the (equidistant) energy mesh where the weights are changing
     370    25068210 :          IF( SIZE(eMesh)>1 .AND. .NOT.l_bloechl) THEN !With bloechl corrections we cannot cut as clean
     371             :             !Extract basic parameters of the equidistant eMesh
     372   400933320 :             eb = MINVAL(eMesh)
     373             :             et = MAXVAL(eMesh)
     374       77240 :             del = eMesh(2)-eMesh(1)
     375             : 
     376             :             !Get last point to the left of the lowest eigenvalue in the tetrahedron
     377       77240 :             nstart = INT((etetra(ind(1))-eb)/del)+1
     378       77240 :             nstart = MAX(1,nstart)
     379             : 
     380             :             !Get first point to the right of the highest eigenvalue in the tetrahedron
     381       77240 :             nend   = INT((etetra(ind(SIZE(etetra)))-eb)/del)+2
     382       77240 :             nend   = MIN(SIZE(eMesh),nend)
     383       77240 :             nend   = MAX(1,nend)
     384             :          ELSE
     385    25068210 :             nstart = 1
     386    25068210 :             nend   = SIZE(eMesh)
     387             :          ENDIF
     388             : 
     389   194421342 :          IF(nstart /= 1) weight(:nstart-1) = 0.0
     390             :          !Calculate the weights
     391    62097536 :          DO ie = nstart, nend
     392   221880378 :             weight(ie) = tetraWeight(eMesh(ie),etetra(ind),icornSorted,vol,film)
     393   155547776 :             IF(l_bloechl) weight(ie) = weight(ie) + bloechl(eMesh(ie),etetra(ind),icornSorted,vol,film)
     394             :          ENDDO
     395             : 
     396             :          !The loop terminates if the energy is larger than
     397             :          !all eigenvalues at the tetrahedron/triangle corners (nend)
     398             :          !For all consecutive values the weight is constant
     399   219541832 :          IF(nend /= SIZE(eMesh)) weight(nend+1:) = weight(nend)
     400             :       ENDIF
     401             : 
     402    25068210 :    END FUNCTION getWeightSingleBand
     403             : 
     404             : END MODULE m_tetrahedronInit

Generated by: LCOV version 1.14