LCOV - code coverage report
Current view: top level - src/xc - xc_perdew_wang.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:4dc10b3) Lines: 146 187 78.1 %
Date: 2024-11-21 06:45:46 Functions: 10 10 100.0 %

          Line data    Source code
       1             : !--------------------------------------------------------------------------------------------------!
       2             : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3             : !   Copyright 2000-2024 CP2K developers group <https://cp2k.org>                                   !
       4             : !                                                                                                  !
       5             : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6             : !--------------------------------------------------------------------------------------------------!
       7             : 
       8             : ! **************************************************************************************************
       9             : !> \brief Calculate the Perdew-Wang correlation potential and
      10             : !>      energy density and ist derivatives with respect to
      11             : !>      the spin-up and spin-down densities up to 3rd order.
      12             : !> \par History
      13             : !>      18-MAR-2002, TCH, working version
      14             : !>      fawzi (04.2004)  : adapted to the new xc interface
      15             : !> \see functionals_utilities
      16             : ! **************************************************************************************************
      17             : MODULE xc_perdew_wang
      18             :    #:include "xc_perdew_wang.fypp"
      19             : 
      20             :    USE kinds, ONLY: dp
      21             :    USE pw_types, ONLY: pw_r3d_rs_type
      22             :    USE xc_derivative_set_types, ONLY: xc_derivative_set_type, &
      23             :                                       xc_dset_get_derivative
      24             :    USE xc_derivative_types, ONLY: xc_derivative_get, &
      25             :                                   xc_derivative_type
      26             :    USE xc_functionals_utilities, ONLY: calc_fx, &
      27             :                                        calc_rs, &
      28             :                                        calc_z, &
      29             :                                        set_util
      30             :    USE xc_input_constants, ONLY: pw_dmc, &
      31             :                                  pw_orig, &
      32             :                                  pw_vmc
      33             :    USE xc_rho_cflags_types, ONLY: xc_rho_cflags_type
      34             :    USE xc_rho_set_types, ONLY: xc_rho_set_get, &
      35             :                                xc_rho_set_type
      36             :    USE xc_derivative_desc, ONLY: deriv_rho, &
      37             :                                  deriv_rhoa, &
      38             :                                  deriv_rhob
      39             : #include "../base/base_uses.f90"
      40             : 
      41             :    IMPLICIT NONE
      42             :    PRIVATE
      43             : 
      44             :    @: global_var_pw92()
      45             :    REAL(KIND=dp), PARAMETER :: &
      46             :       epsilon = 5.E-13_dp, &
      47             :       fpp = 0.584822362263464620726223866376013788782_dp ! d^2f(0)/dz^2
      48             :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'xc_perdew_wang'
      49             : 
      50             :    PUBLIC :: perdew_wang_info, perdew_wang_lda_eval, perdew_wang_lsd_eval, perdew_wang_fxc_calc
      51             : 
      52             : CONTAINS
      53             : 
      54             : ! **************************************************************************************************
      55             : !> \brief Return some info on the functionals.
      56             : !> \param method ...
      57             : !> \param lsd ...
      58             : !> \param reference full reference
      59             : !> \param shortform short reference
      60             : !> \param needs ...
      61             : !> \param max_deriv ...
      62             : !> \param scale ...
      63             : ! **************************************************************************************************
      64         301 :    SUBROUTINE perdew_wang_info(method, lsd, reference, shortform, needs, &
      65             :                                max_deriv, scale)
      66             :       INTEGER, INTENT(in)                                :: method
      67             :       LOGICAL, INTENT(in)                                :: lsd
      68             :       CHARACTER(LEN=*), INTENT(OUT), OPTIONAL            :: reference, shortform
      69             :       TYPE(xc_rho_cflags_type), INTENT(inout), OPTIONAL  :: needs
      70             :       INTEGER, INTENT(out), OPTIONAL                     :: max_deriv
      71             :       REAL(kind=dp), INTENT(in)                          :: scale
      72             : 
      73             :       CHARACTER(len=3)                                   :: p_string
      74             : 
      75         301 :       SELECT CASE (method)
      76             :       CASE DEFAULT
      77           0 :          CPABORT("Unsupported parametrization")
      78             :       CASE (pw_orig)
      79         301 :          p_string = 'PWO'
      80             :       CASE (pw_dmc)
      81           0 :          p_string = 'DMC'
      82             :       CASE (pw_vmc)
      83           0 :          p_string = 'VMC'
      84             :       END SELECT
      85             : 
      86         301 :       IF (PRESENT(reference)) THEN
      87             :          reference = "J. P. Perdew and Yue Wang," &
      88             :                      //" Phys. Rev. B 45, 13244 (1992)" &
      89          13 :                      //"["//TRIM(p_string)//"]"
      90          13 :          IF (scale /= 1._dp) THEN
      91             :             WRITE (reference(LEN_TRIM(reference) + 1:LEN(reference)), "('s=',f5.3)") &
      92           0 :                scale
      93             :          END IF
      94          13 :          IF (.NOT. lsd) THEN
      95          13 :             IF (LEN_TRIM(reference) + 6 < LEN(reference)) THEN
      96          13 :                reference(LEN_TRIM(reference) + 1:LEN_TRIM(reference) + 7) = ' {LDA}'
      97             :             END IF
      98             :          END IF
      99             :       END IF
     100         301 :       IF (PRESENT(shortform)) THEN
     101             :          shortform = "J. P. Perdew et al., PRB 45, 13244 (1992)" &
     102          13 :                      //"["//TRIM(p_string)//"]"
     103          13 :          IF (scale /= 1._dp) THEN
     104             :             WRITE (shortform(LEN_TRIM(shortform) + 1:LEN(shortform)), "('s=',f5.3)") &
     105           0 :                scale
     106             :          END IF
     107          13 :          IF (.NOT. lsd) THEN
     108          13 :             IF (LEN_TRIM(shortform) + 6 < LEN(shortform)) THEN
     109          13 :                shortform(LEN_TRIM(shortform) + 1:LEN_TRIM(shortform) + 7) = ' {LDA}'
     110             :             END IF
     111             :          END IF
     112             :       END IF
     113         301 :       IF (PRESENT(needs)) THEN
     114         288 :          IF (lsd) THEN
     115          24 :             needs%rho_spin = .TRUE.
     116             :          ELSE
     117         264 :             needs%rho = .TRUE.
     118             :          END IF
     119             :       END IF
     120         301 :       IF (PRESENT(max_deriv)) max_deriv = 3
     121             : 
     122         301 :    END SUBROUTINE perdew_wang_info
     123             : 
     124        1130 :    @: init_pw92()
     125             : 
     126             : ! **************************************************************************************************
     127             : !> \brief Calculate the correlation energy and its derivatives
     128             : !>      wrt to rho (the electron density) up to 3rd order. This
     129             : !>      is the LDA version of the Perdew-Wang correlation energy
     130             : !>      If no order argument is given, then the routine calculates
     131             : !>      just the energy.
     132             : !> \param method ...
     133             : !> \param rho_set ...
     134             : !> \param deriv_set ...
     135             : !> \param order order of derivatives to calculate
     136             : !>      order must lie between -3 and 3. If it is negative then only
     137             : !>      that order will be calculated, otherwise all derivatives up to
     138             : !>      that order will be calculated.
     139             : !> \param scale ...
     140             : ! **************************************************************************************************
     141         392 :    SUBROUTINE perdew_wang_lda_eval(method, rho_set, deriv_set, order, scale)
     142             : 
     143             :       INTEGER, INTENT(in)                                :: method
     144             :       TYPE(xc_rho_set_type), INTENT(IN)                  :: rho_set
     145             :       TYPE(xc_derivative_set_type), INTENT(IN)           :: deriv_set
     146             :       INTEGER, INTENT(in)                                :: order
     147             :       REAL(kind=dp), INTENT(in)                          :: scale
     148             : 
     149             :       CHARACTER(len=*), PARAMETER :: routineN = 'perdew_wang_lda_eval'
     150             : 
     151             :       INTEGER                                            :: npoints, timer_handle
     152             :       INTEGER, DIMENSION(2, 3)                  :: bo
     153             :       REAL(KIND=dp)                                      :: rho_cutoff
     154         196 :       REAL(KIND=dp), CONTIGUOUS, DIMENSION(:, :, :), POINTER         :: dummy, e_0, e_rho, e_rho_rho, &
     155         196 :                                                                         e_rho_rho_rho, rho
     156             :       TYPE(xc_derivative_type), POINTER                  :: deriv
     157             : 
     158         196 :       CALL timeset(routineN, timer_handle)
     159         196 :       NULLIFY (rho, e_0, e_rho, e_rho_rho, e_rho_rho_rho, dummy)
     160             :       CALL xc_rho_set_get(rho_set, rho=rho, &
     161         196 :                           local_bounds=bo, rho_cutoff=rho_cutoff)
     162         196 :       npoints = (bo(2, 1) - bo(1, 1) + 1)*(bo(2, 2) - bo(1, 2) + 1)*(bo(2, 3) - bo(1, 3) + 1)
     163             : 
     164         196 :       CALL perdew_wang_init(method, rho_cutoff)
     165             : 
     166         196 :       dummy => rho
     167             : 
     168         196 :       e_0 => dummy
     169         196 :       e_rho => dummy
     170         196 :       e_rho_rho => dummy
     171         196 :       e_rho_rho_rho => dummy
     172             : 
     173         196 :       IF (order >= 0) THEN
     174             :          deriv => xc_dset_get_derivative(deriv_set, [INTEGER::], &
     175         196 :                                          allocate_deriv=.TRUE.)
     176         196 :          CALL xc_derivative_get(deriv, deriv_data=e_0)
     177             :       END IF
     178         196 :       IF (order >= 1 .OR. order == -1) THEN
     179             :          deriv => xc_dset_get_derivative(deriv_set, [deriv_rho], &
     180         196 :                                          allocate_deriv=.TRUE.)
     181         196 :          CALL xc_derivative_get(deriv, deriv_data=e_rho)
     182             :       END IF
     183         196 :       IF (order >= 2 .OR. order == -2) THEN
     184             :          deriv => xc_dset_get_derivative(deriv_set, [deriv_rho, deriv_rho], &
     185           0 :                                          allocate_deriv=.TRUE.)
     186           0 :          CALL xc_derivative_get(deriv, deriv_data=e_rho_rho)
     187             :       END IF
     188         196 :       IF (order >= 3 .OR. order == -3) THEN
     189             :          deriv => xc_dset_get_derivative(deriv_set, [deriv_rho, deriv_rho, deriv_rho], &
     190           0 :                                          allocate_deriv=.TRUE.)
     191           0 :          CALL xc_derivative_get(deriv, deriv_data=e_rho_rho_rho)
     192             :       END IF
     193         196 :       IF (order > 3 .OR. order < -3) THEN
     194           0 :          CPABORT("derivatives bigger than 3 not implemented")
     195             :       END IF
     196             : 
     197             :       CALL perdew_wang_lda_calc(rho, e_0, e_rho, e_rho_rho, e_rho_rho_rho, &
     198         196 :                                 npoints, order, scale)
     199             : 
     200         196 :       CALL timestop(timer_handle)
     201             : 
     202         196 :    END SUBROUTINE perdew_wang_lda_eval
     203             : 
     204             : ! **************************************************************************************************
     205             : !> \brief ...
     206             : !> \param rho ...
     207             : !> \param e_0 ...
     208             : !> \param e_rho ...
     209             : !> \param e_rho_rho ...
     210             : !> \param e_rho_rho_rho ...
     211             : !> \param npoints ...
     212             : !> \param order ...
     213             : !> \param scale ...
     214             : ! **************************************************************************************************
     215         196 :    SUBROUTINE perdew_wang_lda_calc(rho, e_0, e_rho, e_rho_rho, e_rho_rho_rho, npoints, order, scale)
     216             :       !FM low level calc routine
     217             :       REAL(KIND=dp), DIMENSION(*), INTENT(in)            :: rho
     218             :       REAL(KIND=dp), DIMENSION(*), INTENT(inout)         :: e_0, e_rho, e_rho_rho, e_rho_rho_rho
     219             :       INTEGER, INTENT(in)                                :: npoints, order
     220             :       REAL(kind=dp), INTENT(in)                          :: scale
     221             : 
     222             :       INTEGER                                            :: abs_order, k
     223             :       REAL(KIND=dp), DIMENSION(0:3)                      :: ed
     224             : 
     225         196 :       abs_order = ABS(order)
     226             : 
     227             : !$OMP PARALLEL DO PRIVATE (k, ed) DEFAULT(NONE)&
     228         196 : !$OMP SHARED(npoints,rho,eps_rho,abs_order,scale,e_0,e_rho,e_rho_rho,e_rho_rho_rho,order)
     229             :       DO k = 1, npoints
     230             : 
     231             :          IF (rho(k) > eps_rho) THEN
     232             : !! order_ is positive as it must be in this case:
     233             : !! ec(:,2) needs ed(:,1) for example
     234             :             CALL pw_lda_ed_loc(rho(k), ed, abs_order)
     235             :             ed(0:abs_order) = scale*ed(0:abs_order)
     236             : 
     237             :             IF (order >= 0) THEN
     238             :                e_0(k) = e_0(k) + rho(k)*ed(0)
     239             :             END IF
     240             :             IF (order >= 1 .OR. order == -1) THEN
     241             :                e_rho(k) = e_rho(k) + ed(0) + rho(k)*ed(1)
     242             :             END IF
     243             :             IF (order >= 2 .OR. order == -2) THEN
     244             :                e_rho_rho(k) = e_rho_rho(k) + 2.0_dp*ed(1) + rho(k)*ed(2)
     245             :             END IF
     246             :             IF (order >= 3 .OR. order == -3) THEN
     247             :                e_rho_rho_rho(k) = e_rho_rho_rho(k) + 3.0_dp*ed(2) + rho(k)*ed(3)
     248             :             END IF
     249             : 
     250             :          END IF
     251             : 
     252             :       END DO
     253             : !$OMP END PARALLEL DO
     254             : 
     255         196 :    END SUBROUTINE perdew_wang_lda_calc
     256             : 
     257             : ! **************************************************************************************************
     258             : !> \brief Calculate the correlation energy and its derivatives
     259             : !>      wrt to rho (the electron density) up to 3rd order. This
     260             : !>      is the LSD version of the Perdew-Wang correlation energy
     261             : !>      If no order argument is given, then the routine calculates
     262             : !>      just the energy.
     263             : !> \param method ...
     264             : !> \param rho_set ...
     265             : !> \param deriv_set ...
     266             : !> \param order order of derivatives to calculate
     267             : !>      order must lie between -3 and 3. If it is negative then only
     268             : !>      that order will be calculated, otherwise all derivatives up to
     269             : !>      that order will be calculated.
     270             : !> \param scale ...
     271             : ! **************************************************************************************************
     272          40 :    SUBROUTINE perdew_wang_lsd_eval(method, rho_set, deriv_set, order, scale)
     273             :       INTEGER, INTENT(in)                                :: method
     274             :       TYPE(xc_rho_set_type), INTENT(IN)                  :: rho_set
     275             :       TYPE(xc_derivative_set_type), INTENT(IN)           :: deriv_set
     276             :       INTEGER, INTENT(IN), OPTIONAL                      :: order
     277             :       REAL(kind=dp), INTENT(in)                          :: scale
     278             : 
     279             :       CHARACTER(len=*), PARAMETER :: routineN = 'perdew_wang_lsd_eval'
     280             : 
     281             :       INTEGER                                            :: npoints, timer_handle
     282             :       INTEGER, DIMENSION(2, 3)                  :: bo
     283             :       REAL(KIND=dp)                                      :: rho_cutoff
     284          20 :       REAL(KIND=dp), CONTIGUOUS, DIMENSION(:, :, :), POINTER         :: a, b, dummy, e_0, ea, eaa, eaaa, eaab, &
     285          20 :                                                                         eab, eabb, eb, ebb, ebbb
     286             :       TYPE(xc_derivative_type), POINTER                  :: deriv
     287             : 
     288          20 :       CALL timeset(routineN, timer_handle)
     289          20 :       NULLIFY (a, b, e_0, ea, eb, eaa, eab, ebb, eaaa, eaab, eabb, ebbb)
     290             :       CALL xc_rho_set_get(rho_set, rhoa=a, rhob=b, &
     291          20 :                           local_bounds=bo, rho_cutoff=rho_cutoff)
     292          20 :       npoints = (bo(2, 1) - bo(1, 1) + 1)*(bo(2, 2) - bo(1, 2) + 1)*(bo(2, 3) - bo(1, 3) + 1)
     293             : 
     294          20 :       CALL perdew_wang_init(method, rho_cutoff)
     295             : 
     296             :       ! meaningful default for the arrays we don't need: let us make compiler
     297             :       ! and debugger happy...
     298          20 :       dummy => a
     299             : 
     300          20 :       e_0 => dummy
     301          20 :       ea => dummy; eb => dummy
     302          20 :       eaa => dummy; eab => dummy; ebb => dummy
     303          20 :       eaaa => dummy; eaab => dummy; eabb => dummy; ebbb => dummy
     304             : 
     305          20 :       IF (order >= 0) THEN
     306             :          deriv => xc_dset_get_derivative(deriv_set, [INTEGER::], &
     307          20 :                                          allocate_deriv=.TRUE.)
     308          20 :          CALL xc_derivative_get(deriv, deriv_data=e_0)
     309             :       END IF
     310          20 :       IF (order >= 1 .OR. order == -1) THEN
     311             :          deriv => xc_dset_get_derivative(deriv_set, [deriv_rhoa], &
     312          20 :                                          allocate_deriv=.TRUE.)
     313          20 :          CALL xc_derivative_get(deriv, deriv_data=ea)
     314             :          deriv => xc_dset_get_derivative(deriv_set, [deriv_rhob], &
     315          20 :                                          allocate_deriv=.TRUE.)
     316          20 :          CALL xc_derivative_get(deriv, deriv_data=eb)
     317             :       END IF
     318          20 :       IF (order >= 2 .OR. order == -2) THEN
     319             :          deriv => xc_dset_get_derivative(deriv_set, [deriv_rhoa, deriv_rhoa], &
     320           0 :                                          allocate_deriv=.TRUE.)
     321           0 :          CALL xc_derivative_get(deriv, deriv_data=eaa)
     322             :          deriv => xc_dset_get_derivative(deriv_set, [deriv_rhoa, deriv_rhob], &
     323           0 :                                          allocate_deriv=.TRUE.)
     324           0 :          CALL xc_derivative_get(deriv, deriv_data=eab)
     325             :          deriv => xc_dset_get_derivative(deriv_set, [deriv_rhob, deriv_rhob], &
     326           0 :                                          allocate_deriv=.TRUE.)
     327           0 :          CALL xc_derivative_get(deriv, deriv_data=ebb)
     328             :       END IF
     329          20 :       IF (order >= 3 .OR. order == -3) THEN
     330             :          deriv => xc_dset_get_derivative(deriv_set, [deriv_rhoa, deriv_rhoa, deriv_rhoa], &
     331           0 :                                          allocate_deriv=.TRUE.)
     332           0 :          CALL xc_derivative_get(deriv, deriv_data=eaaa)
     333             :          deriv => xc_dset_get_derivative(deriv_set, [deriv_rhoa, deriv_rhoa, deriv_rhob], &
     334           0 :                                          allocate_deriv=.TRUE.)
     335           0 :          CALL xc_derivative_get(deriv, deriv_data=eaab)
     336             :          deriv => xc_dset_get_derivative(deriv_set, [deriv_rhoa, deriv_rhob, deriv_rhob], &
     337           0 :                                          allocate_deriv=.TRUE.)
     338           0 :          CALL xc_derivative_get(deriv, deriv_data=eabb)
     339             :          deriv => xc_dset_get_derivative(deriv_set, [deriv_rhob, deriv_rhob, deriv_rhob], &
     340           0 :                                          allocate_deriv=.TRUE.)
     341           0 :          CALL xc_derivative_get(deriv, deriv_data=ebbb)
     342             :       END IF
     343          20 :       IF (order > 3 .OR. order < -3) THEN
     344           0 :          CPABORT("derivatives bigger than 3 not implemented")
     345             :       END IF
     346             : 
     347             :       CALL perdew_wang_lsd_calc(a, b, e_0, ea, eb, eaa, eab, ebb, eaaa, eaab, eabb, &
     348          20 :                                 ebbb, npoints, order, scale)
     349             : 
     350          20 :       CALL timestop(timer_handle)
     351             : 
     352          20 :    END SUBROUTINE perdew_wang_lsd_eval
     353             : 
     354             : ! **************************************************************************************************
     355             : !> \brief ...
     356             : !> \param rhoa ...
     357             : !> \param rhob ...
     358             : !> \param e_0 ...
     359             : !> \param ea ...
     360             : !> \param eb ...
     361             : !> \param eaa ...
     362             : !> \param eab ...
     363             : !> \param ebb ...
     364             : !> \param eaaa ...
     365             : !> \param eaab ...
     366             : !> \param eabb ...
     367             : !> \param ebbb ...
     368             : !> \param npoints ...
     369             : !> \param order ...
     370             : !> \param scale ...
     371             : ! **************************************************************************************************
     372          20 :    SUBROUTINE perdew_wang_lsd_calc(rhoa, rhob, e_0, ea, eb, eaa, eab, ebb, eaaa, eaab, eabb, &
     373             :                                    ebbb, npoints, order, scale)
     374             :       !FM low-level computation routine
     375             :       REAL(KIND=dp), DIMENSION(*), INTENT(in)            :: rhoa, rhob
     376             :       REAL(KIND=dp), DIMENSION(*), INTENT(inout)         :: e_0, ea, eb, eaa, eab, ebb, eaaa, eaab, &
     377             :                                                             eabb, ebbb
     378             :       INTEGER, INTENT(in)                                :: npoints, order
     379             :       REAL(kind=dp), INTENT(in)                          :: scale
     380             : 
     381             :       INTEGER                                            :: abs_order, k
     382             :       REAL(KIND=dp)                                      :: rho
     383             :       REAL(KIND=dp), DIMENSION(0:9)                      :: ed
     384             : 
     385          20 :       abs_order = ABS(order)
     386             : 
     387             : !$OMP PARALLEL DO PRIVATE (k, rho, ed) DEFAULT(NONE)&
     388          20 : !$OMP SHARED(npoints,rhoa,rhob,eps_rho,abs_order,order,e_0,ea,eb,eaa,eab,ebb,eaaa,eaab,eabb,ebbb,scale)
     389             :       DO k = 1, npoints
     390             : 
     391             :          rho = rhoa(k) + rhob(k)
     392             :          IF (rho > eps_rho) THEN
     393             : 
     394             :             ed = 0.0_dp
     395             :             CALL pw_lsd_ed_loc(rhoa(k), rhob(k), ed, abs_order)
     396             :             ed = ed*scale
     397             : 
     398             :             IF (order >= 0) THEN
     399             :                e_0(k) = e_0(k) + rho*ed(0)
     400             :             END IF
     401             :             IF (order >= 1 .OR. order == -1) THEN
     402             :                ea(k) = ea(k) + ed(0) + rho*ed(1)
     403             :                eb(k) = eb(k) + ed(0) + rho*ed(2)
     404             :             END IF
     405             :             IF (order >= 2 .OR. order == -2) THEN
     406             :                eaa(k) = eaa(k) + 2.0_dp*ed(1) + rho*ed(3)
     407             :                eab(k) = eab(k) + ed(1) + ed(2) + rho*ed(4)
     408             :                ebb(k) = ebb(k) + 2.0_dp*ed(2) + rho*ed(5)
     409             :             END IF
     410             :             IF (order >= 3 .OR. order == -3) THEN
     411             :                eaaa(k) = eaaa(k) + 3.0_dp*ed(3) + rho*ed(6)
     412             :                eaab(k) = eaab(k) + 2.0_dp*ed(4) + ed(3) + rho*ed(7)
     413             :                eabb(k) = eabb(k) + 2.0_dp*ed(4) + ed(5) + rho*ed(8)
     414             :                ebbb(k) = ebbb(k) + 3.0_dp*ed(5) + rho*ed(9)
     415             :             END IF
     416             : 
     417             :          END IF
     418             : 
     419             :       END DO
     420             : 
     421          20 :    END SUBROUTINE perdew_wang_lsd_calc
     422             : 
     423             : ! **************************************************************************************************
     424             : !> \brief ...
     425             : !> \param rho_a ...
     426             : !> \param rho_b ...
     427             : !> \param fxc_aa ...
     428             : !> \param fxc_ab ...
     429             : !> \param fxc_bb ...
     430             : !> \param scalec ...
     431             : !> \param eps_rho ...
     432             : ! **************************************************************************************************
     433          10 :    SUBROUTINE perdew_wang_fxc_calc(rho_a, rho_b, fxc_aa, fxc_ab, fxc_bb, scalec, eps_rho)
     434             :       TYPE(pw_r3d_rs_type), INTENT(IN)                          :: rho_a, rho_b
     435             :       TYPE(pw_r3d_rs_type), INTENT(INOUT)                       :: fxc_aa, fxc_ab, fxc_bb
     436             :       REAL(kind=dp), INTENT(in)                          :: scalec, eps_rho
     437             : 
     438             :       INTEGER                                            :: i, j, k
     439             :       INTEGER, DIMENSION(2, 3)                           :: bo
     440             :       REAL(KIND=dp)                                      :: rho, rhoa, rhob, eaa, eab, ebb
     441             :       REAL(KIND=dp), DIMENSION(0:9)                      :: ed
     442             : 
     443          10 :       CALL perdew_wang_init(pw_orig, eps_rho)
     444         100 :       bo(1:2, 1:3) = rho_a%pw_grid%bounds_local(1:2, 1:3)
     445             : !$OMP PARALLEL DO PRIVATE(i,j,k,rho,rhoa,rhob,ed,eaa,eab,ebb) DEFAULT(NONE)&
     446          10 : !$OMP SHARED(bo,rho_a,rho_b,fxc_aa,fxc_ab,fxc_bb,scalec,eps_rho)
     447             :       DO k = bo(1, 3), bo(2, 3)
     448             :          DO j = bo(1, 2), bo(2, 2)
     449             :             DO i = bo(1, 1), bo(2, 1)
     450             :                rhoa = rho_a%array(i, j, k)
     451             :                rhob = rho_b%array(i, j, k)
     452             :                rho = rhoa + rhob
     453             :                IF (rho > eps_rho) THEN
     454             :                   ed = 0.0_dp
     455             :                   CALL pw_lsd_ed_loc(rhoa, rhob, ed, 2)
     456             :                   ed = ed*scalec
     457             :                   eaa = 2.0_dp*ed(1) + rho*ed(3)
     458             :                   eab = ed(1) + ed(2) + rho*ed(4)
     459             :                   ebb = 2.0_dp*ed(2) + rho*ed(5)
     460             :                   fxc_aa%array(i, j, k) = fxc_aa%array(i, j, k) + eaa
     461             :                   fxc_ab%array(i, j, k) = fxc_ab%array(i, j, k) + eab
     462             :                   fxc_bb%array(i, j, k) = fxc_bb%array(i, j, k) + ebb
     463             :                END IF
     464             :             END DO
     465             :          END DO
     466             :       END DO
     467             : 
     468          10 :    END SUBROUTINE perdew_wang_fxc_calc
     469             : 
     470    15261532 :    @:calc_g()
     471             : 
     472             : ! **************************************************************************************************
     473             : !> \brief ...
     474             : !> \param rho ...
     475             : !> \param ed ...
     476             : !> \param order ...
     477             : ! **************************************************************************************************
     478    10647850 :    SUBROUTINE pw_lda_ed_loc(rho, ed, order)
     479             : 
     480             :       REAL(KIND=dp), INTENT(IN)                          :: rho
     481             :       REAL(KIND=dp), DIMENSION(0:), INTENT(OUT)          :: ed
     482             :       INTEGER, INTENT(IN)                                :: order
     483             : 
     484             :       INTEGER                                            :: m, order_
     485             :       LOGICAL, DIMENSION(0:3)                            :: calc
     486             :       REAL(KIND=dp), DIMENSION(0:3)                      :: e0, r
     487             : 
     488    10647850 :       order_ = order
     489    53239250 :       ed = 0
     490    10647850 :       calc = .FALSE.
     491             : 
     492    10647850 :       IF (order_ >= 0) THEN
     493    31943550 :          calc(0:order_) = .TRUE.
     494             :       ELSE
     495           0 :          order_ = -1*order_
     496           0 :          calc(order_) = .TRUE.
     497             :       END IF
     498             : 
     499    10647850 :       CALL calc_rs(rho, r(0))
     500    10647850 :       CALL calc_g(r(0), 0, e0, order_)
     501             : 
     502    10647850 :       IF (order_ >= 1) r(1) = (-1.0_dp/3.0_dp)*r(0)/rho
     503    10647850 :       IF (order_ >= 2) r(2) = (-4.0_dp/3.0_dp)*r(1)/rho
     504    10647850 :       IF (order_ >= 3) r(3) = (-7.0_dp/3.0_dp)*r(2)/rho
     505             : 
     506    10647850 :       m = 0
     507    10647850 :       IF (calc(0)) THEN
     508    10647850 :          ed(m) = e0(0)
     509    10647850 :          m = m + 1
     510             :       END IF
     511    10647850 :       IF (calc(1)) THEN
     512    10647850 :          ed(m) = e0(1)*r(1)
     513    10647850 :          m = m + 1
     514             :       END IF
     515    10647850 :       IF (calc(2)) THEN
     516           0 :          ed(m) = e0(2)*r(1)**2 + e0(1)*r(2)
     517           0 :          m = m + 1
     518             :       END IF
     519    10647850 :       IF (calc(3)) THEN
     520           0 :          ed(m) = e0(3)*r(1)**3 + e0(2)*3.0_dp*r(1)*r(2) + e0(1)*r(3)
     521             :       END IF
     522             : 
     523    10647850 :    END SUBROUTINE pw_lda_ed_loc
     524             : 
     525             : ! **************************************************************************************************
     526             : !> \brief ...
     527             : !> \param a ...
     528             : !> \param b ...
     529             : !> \param ed ...
     530             : !> \param order ...
     531             : ! **************************************************************************************************
     532     1537894 :    SUBROUTINE pw_lsd_ed_loc(a, b, ed, order)
     533             : 
     534             :       REAL(KIND=dp), INTENT(IN)                          :: a, b
     535             :       REAL(KIND=dp), DIMENSION(0:), INTENT(OUT)          :: ed
     536             :       INTEGER, INTENT(IN)                                :: order
     537             : 
     538             :       INTEGER                                            :: m, order_
     539             :       LOGICAL, DIMENSION(0:3)                            :: calc
     540             :       REAL(KIND=dp)                                      :: rho, tr, trr, trrr, trrz, trz, trzz, tz, &
     541             :                                                             tzz, tzzz
     542             :       REAL(KIND=dp), DIMENSION(0:3)                      :: ac, e0, e1, f, r
     543             :       REAL(KIND=dp), DIMENSION(0:3, 0:3)                 :: z
     544             : 
     545     1537894 :       order_ = order
     546     1537894 :       calc = .FALSE.
     547             : 
     548     1537894 :       IF (order_ > 0) THEN
     549     5240326 :          calc(0:order_) = .TRUE.
     550             :       ELSE
     551           0 :          order_ = -1*order_
     552           0 :          calc(order_) = .TRUE.
     553             :       END IF
     554             : 
     555     1537894 :       rho = a + b
     556             : 
     557     1537894 :       CALL calc_fx(a, b, f(0:order_), order_)
     558     1537894 :       CALL calc_rs(rho, r(0))
     559     1537894 :       CALL calc_g(r(0), -1, ac(0:order_), order_)
     560     1537894 :       CALL calc_g(r(0), 0, e0(0:order_), order_)
     561     1537894 :       CALL calc_g(r(0), 1, e1(0:order_), order_)
     562     1537894 :       CALL calc_z(a, b, z(0:order_, 0:order_), order_)
     563             : 
     564             : !! calculate first partial derivatives
     565     1537894 :       IF (order_ >= 1) THEN
     566     1537894 :          r(1) = (-1.0_dp/3.0_dp)*r(0)/rho
     567             :          tr = e0(1) &
     568             :               + fpp*ac(1)*f(0) &
     569             :               - fpp*ac(1)*f(0)*z(0, 0)**4 &
     570     1537894 :               + (e1(1) - e0(1))*f(0)*z(0, 0)**4
     571             :          tz = fpp*ac(0)*f(1) &
     572             :               - fpp*ac(0)*f(1)*z(0, 0)**4 &
     573             :               - fpp*ac(0)*f(0)*4.0_dp*z(0, 0)**3 &
     574             :               + (e1(0) - e0(0))*f(1)*z(0, 0)**4 &
     575     1537894 :               + (e1(0) - e0(0))*f(0)*4.0_dp*z(0, 0)**3
     576             :       END IF
     577             : 
     578             : !! calculate second partial derivatives
     579     1537894 :       IF (order_ >= 2) THEN
     580      626644 :          r(2) = (-4.0_dp/3.0_dp)*r(1)/rho
     581             :          trr = e0(2) &
     582             :                + fpp*ac(2)*f(0) &
     583             :                - fpp*ac(2)*f(0)*z(0, 0)**4 &
     584      626644 :                + (e1(2) - e0(2))*f(0)*z(0, 0)**4
     585             :          trz = fpp*ac(1)*f(1) &
     586             :                - fpp*ac(1)*f(1)*z(0, 0)**4 &
     587             :                - fpp*ac(1)*f(0)*4.0_dp*z(0, 0)**3 &
     588             :                + (e1(1) - e0(1))*f(1)*z(0, 0)**4 &
     589      626644 :                + (e1(1) - e0(1))*f(0)*4.0_dp*z(0, 0)**3
     590             :          tzz = fpp*ac(0)*f(2) &
     591             :                - fpp*ac(0)*f(2)*z(0, 0)**4 &
     592             :                - fpp*ac(0)*f(1)*8.0_dp*z(0, 0)**3 &
     593             :                - fpp*ac(0)*f(0)*12.0_dp*z(0, 0)**2 &
     594             :                + (e1(0) - e0(0))*f(2)*z(0, 0)**4 &
     595             :                + (e1(0) - e0(0))*f(1)*8.0_dp*z(0, 0)**3 &
     596      626644 :                + (e1(0) - e0(0))*f(0)*12.0_dp*z(0, 0)**2
     597             :       END IF
     598             : 
     599             : !! calculate third derivatives
     600     1537894 :       IF (order_ >= 3) THEN
     601             : 
     602           0 :          r(3) = (-7.0_dp/3.0_dp)*r(2)/rho
     603             : 
     604             :          trrr = e0(3) &
     605             :                 + fpp*ac(3)*f(0) &
     606             :                 - fpp*ac(3)*f(0)*z(0, 0)**4 &
     607           0 :                 + (e1(3) - e0(3))*f(0)*z(0, 0)**4
     608             : 
     609             :          trrz = fpp*ac(2)*f(1) &
     610             :                 - fpp*ac(2)*f(1)*z(0, 0)**4 &
     611             :                 - fpp*ac(2)*f(0)*4.0_dp*z(0, 0)**3 &
     612             :                 + (e1(2) - e0(2))*f(1)*z(0, 0)**4 &
     613           0 :                 + (e1(2) - e0(2))*f(0)*4.0_dp*z(0, 0)**3
     614             : 
     615             :          trzz = fpp*ac(1)*f(2) &
     616             :                 - fpp*ac(1)*f(2)*z(0, 0)**4 &
     617             :                 - fpp*ac(1)*f(1)*8.0_dp*z(0, 0)**3 &
     618             :                 - fpp*ac(1)*f(0)*12.0_dp*z(0, 0)**2 &
     619             :                 + (e1(1) - e0(1))*f(2)*z(0, 0)**4 &
     620             :                 + (e1(1) - e0(1))*f(1)*8.0_dp*z(0, 0)**3 &
     621           0 :                 + (e1(1) - e0(1))*f(0)*12.0_dp*z(0, 0)**2
     622             : 
     623             :          tzzz = fpp*ac(0)*f(3) &
     624             :                 - fpp*ac(0)*f(3)*z(0, 0)**4 &
     625             :                 - fpp*ac(0)*f(2)*12.0_dp*z(0, 0)**3 &
     626             :                 - fpp*ac(0)*f(1)*36.0_dp*z(0, 0)**2 &
     627             :                 - fpp*ac(0)*f(0)*24.0_dp*z(0, 0) &
     628             :                 + (e1(0) - e0(0))*f(3)*z(0, 0)**4 &
     629             :                 + (e1(0) - e0(0))*f(2)*12.0_dp*z(0, 0)**3 &
     630             :                 + (e1(0) - e0(0))*f(1)*36.0_dp*z(0, 0)**2 &
     631           0 :                 + (e1(0) - e0(0))*f(0)*24.0_dp*z(0, 0)
     632             :       END IF
     633             : 
     634     1537894 :       m = 0
     635     1537894 :       IF (calc(0)) THEN
     636             :          ed(m) = e0(0) &
     637             :                  + fpp*ac(0)*f(0)*(1.0_dp - z(0, 0)**4) &
     638     1537894 :                  + (e1(0) - e0(0))*f(0)*z(0, 0)**4
     639     1537894 :          m = m + 1
     640             :       END IF
     641     1537894 :       IF (calc(1)) THEN
     642     1537894 :          ed(m) = tr*r(1) + tz*z(1, 0)
     643     1537894 :          ed(m + 1) = tr*r(1) + tz*z(0, 1)
     644     1537894 :          m = m + 2
     645             :       END IF
     646     1537894 :       IF (calc(2)) THEN
     647             :          ed(m) = trr*r(1)**2 + 2.0_dp*trz*r(1)*z(1, 0) &
     648      626644 :                  + tr*r(2) + tzz*z(1, 0)**2 + tz*z(2, 0)
     649             :          ed(m + 1) = trr*r(1)**2 + trz*r(1)*(z(0, 1) + z(1, 0)) &
     650      626644 :                      + tr*r(2) + tzz*z(1, 0)*z(0, 1) + tz*z(1, 1)
     651             :          ed(m + 2) = trr*r(1)**2 + 2.0_dp*trz*r(1)*z(0, 1) &
     652      626644 :                      + tr*r(2) + tzz*z(0, 1)**2 + tz*z(0, 2)
     653      626644 :          m = m + 3
     654             :       END IF
     655     1537894 :       IF (calc(3)) THEN
     656             :          ed(m) = &
     657             :             trrr*r(1)**3 + 3.0_dp*trrz*r(1)**2*z(1, 0) &
     658             :             + 3.0_dp*trr*r(1)*r(2) + 3.0_dp*trz*r(2)*z(1, 0) + tr*r(3) &
     659             :             + 3.0_dp*trzz*r(1)*z(1, 0)**2 + tzzz*z(1, 0)**3 &
     660             :             + 3.0_dp*trz*r(1)*z(2, 0) &
     661           0 :             + 3.0_dp*tzz*z(1, 0)*z(2, 0) + tz*z(3, 0)
     662             :          ed(m + 1) = &
     663             :             trrr*r(1)**3 + trrz*r(1)**2*(2.0_dp*z(1, 0) + z(0, 1)) &
     664             :             + 2.0_dp*trzz*r(1)*z(1, 0)*z(0, 1) &
     665             :             + 2.0_dp*trz*(r(2)*z(1, 0) + r(1)*z(1, 1)) &
     666             :             + 3.0_dp*trr*r(2)*r(1) + trz*r(2)*z(0, 1) + tr*r(3) &
     667             :             + trzz*r(1)*z(1, 0)**2 + tzzz*z(1, 0)**2*z(0, 1) &
     668             :             + 2.0_dp*tzz*z(1, 0)*z(1, 1) &
     669           0 :             + trz*r(1)*z(2, 0) + tzz*z(2, 0)*z(0, 1) + tz*z(2, 1)
     670             :          ed(m + 2) = &
     671             :             trrr*r(1)**3 + trrz*r(1)**2*(2.0_dp*z(0, 1) + z(1, 0)) &
     672             :             + 2.0_dp*trzz*r(1)*z(0, 1)*z(1, 0) &
     673             :             + 2.0_dp*trz*(r(2)*z(0, 1) + r(1)*z(1, 1)) &
     674             :             + 3.0_dp*trr*r(2)*r(1) + trz*r(2)*z(1, 0) + tr*r(3) &
     675             :             + trzz*r(1)*z(0, 1)**2 + tzzz*z(0, 1)**2*z(1, 0) &
     676             :             + 2.0_dp*tzz*z(0, 1)*z(1, 1) &
     677           0 :             + trz*r(1)*z(0, 2) + tzz*z(0, 2)*z(1, 0) + tz*z(1, 2)
     678             :          ed(m + 3) = &
     679             :             trrr*r(1)**3 + 3.0_dp*trrz*r(1)**2*z(0, 1) &
     680             :             + 3.0_dp*trr*r(1)*r(2) + 3.0_dp*trz*r(2)*z(0, 1) + tr*r(3) &
     681             :             + 3.0_dp*trzz*r(1)*z(0, 1)**2 + tzzz*z(0, 1)**3 &
     682             :             + 3.0_dp*trz*r(1)*z(0, 2) &
     683           0 :             + 3.0_dp*tzz*z(0, 1)*z(0, 2) + tz*z(0, 3)
     684             :       END IF
     685             : 
     686     1537894 :    END SUBROUTINE pw_lsd_ed_loc
     687             : 
     688             : END MODULE xc_perdew_wang

Generated by: LCOV version 1.15