LCOV - code coverage report
Current view: top level - src/xc - xc_perdew_wang.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:37370f3) Lines: 77.6 % 183 142
Test Date: 2026-11-05 01:01:37 Functions: 100.0 % 10 10

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

Generated by: LCOV version 2.0-1