LCOV - code coverage report
Current view: top level - src/xc - xc.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:936074a) Lines: 61.3 % 1535 941
Test Date: 2025-12-04 06:27:48 Functions: 87.9 % 33 29

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2025 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \brief Exchange and Correlation functional calculations
      10              : !> \par History
      11              : !>      (13-Feb-2001) JGH, based on earlier version of apsi
      12              : !>      02.2003 Many many changes [fawzi]
      13              : !>      03.2004 new xc interface [fawzi]
      14              : !>      04.2004 kinetic functionals [fawzi]
      15              : !> \author fawzi
      16              : ! **************************************************************************************************
      17              : MODULE xc
      18              :    #:include 'xc.fypp'
      19              :    USE cp_array_utils, ONLY: cp_3d_r_cp_type
      20              :    USE cp_linked_list_xc_deriv, ONLY: cp_sll_xc_deriv_next, &
      21              :                                       cp_sll_xc_deriv_type
      22              :    USE cp_log_handling, ONLY: cp_get_default_logger, &
      23              :                               cp_logger_get_default_unit_nr, &
      24              :                               cp_logger_type, &
      25              :                               cp_to_string
      26              :    USE input_section_types, ONLY: section_get_ival, &
      27              :                                   section_get_lval, &
      28              :                                   section_get_rval, &
      29              :                                   section_vals_get_subs_vals, &
      30              :                                   section_vals_type, &
      31              :                                   section_vals_val_get
      32              :    USE kahan_sum, ONLY: accurate_dot_product, &
      33              :                         accurate_sum
      34              :    USE kinds, ONLY: default_path_length, &
      35              :                     dp
      36              :    USE pw_grid_types, ONLY: PW_MODE_DISTRIBUTED, &
      37              :                             pw_grid_type
      38              :    USE pw_methods, ONLY: pw_axpy, &
      39              :                          pw_copy, &
      40              :                          pw_derive, &
      41              :                          pw_scale, &
      42              :                          pw_transfer, &
      43              :                          pw_zero, pw_integrate_function
      44              :    USE pw_pool_types, ONLY: &
      45              :       pw_pool_type
      46              :    USE pw_types, ONLY: &
      47              :       pw_c1d_gs_type, pw_r3d_rs_type
      48              :    USE xc_derivative_desc, ONLY: &
      49              :       deriv_rho, deriv_rhoa, deriv_rhob, &
      50              :       deriv_norm_drhoa, deriv_norm_drhob, deriv_norm_drho, deriv_tau_a, deriv_tau_b, deriv_tau, &
      51              :       deriv_laplace_rho, deriv_laplace_rhoa, deriv_laplace_rhob, id_to_desc
      52              :    USE xc_derivative_set_types, ONLY: xc_derivative_set_type, &
      53              :                                       xc_dset_create, &
      54              :                                       xc_dset_get_derivative, &
      55              :                                       xc_dset_release, &
      56              :                                       xc_dset_zero_all, xc_dset_recover_pw
      57              :    USE xc_derivative_types, ONLY: xc_derivative_get, &
      58              :                                   xc_derivative_type
      59              :    USE xc_derivatives, ONLY: xc_functionals_eval, &
      60              :                              xc_functionals_get_needs
      61              :    USE xc_input_constants, ONLY: &
      62              :       xc_debug_new_routine, xc_default_f_routine, xc_test_lsd_f_routine
      63              :    USE xc_rho_cflags_types, ONLY: xc_rho_cflags_type
      64              :    USE xc_rho_set_types, ONLY: xc_rho_set_create, &
      65              :                                xc_rho_set_get, &
      66              :                                xc_rho_set_release, &
      67              :                                xc_rho_set_type, &
      68              :                                xc_rho_set_update, xc_rho_set_recover_pw
      69              :    USE xc_util, ONLY: xc_pw_smooth, xc_pw_laplace, xc_pw_divergence, xc_requires_tmp_g
      70              : #include "../base/base_uses.f90"
      71              : 
      72              :    IMPLICIT NONE
      73              :    PRIVATE
      74              :    PUBLIC :: xc_vxc_pw_create1, xc_vxc_pw_create, &
      75              :              xc_exc_calc, xc_calc_2nd_deriv_analytical, xc_calc_2nd_deriv_numerical, xc_calc_3rd_deriv_analytical, &
      76              :              xc_calc_2nd_deriv, xc_prep_2nd_deriv, xc_prep_3rd_deriv, divide_by_norm_drho, smooth_cutoff, &
      77              :              xc_uses_kinetic_energy_density, xc_uses_norm_drho
      78              :    PUBLIC :: calc_xc_density
      79              : 
      80              :    LOGICAL, PRIVATE, PARAMETER :: debug_this_module = .TRUE.
      81              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'xc'
      82              : 
      83              : CONTAINS
      84              : 
      85              : ! **************************************************************************************************
      86              : !> \brief ...
      87              : !> \param xc_fun_section ...
      88              : !> \param lsd ...
      89              : !> \return ...
      90              : ! **************************************************************************************************
      91         7696 :    FUNCTION xc_uses_kinetic_energy_density(xc_fun_section, lsd) RESULT(res)
      92              :       TYPE(section_vals_type), POINTER, INTENT(IN) :: xc_fun_section
      93              :       LOGICAL, INTENT(IN) :: lsd
      94              :       LOGICAL :: res
      95              : 
      96              :       TYPE(xc_rho_cflags_type)                           :: needs
      97              : 
      98              :       needs = xc_functionals_get_needs(xc_fun_section, &
      99              :                                        lsd=lsd, &
     100        15392 :                                        calc_potential=.FALSE.)
     101         7696 :       res = (needs%tau_spin .OR. needs%tau)
     102              : 
     103         7696 :    END FUNCTION xc_uses_kinetic_energy_density
     104              : 
     105              : ! **************************************************************************************************
     106              : !> \brief ...
     107              : !> \param xc_fun_section ...
     108              : !> \param lsd ...
     109              : !> \return ...
     110              : ! **************************************************************************************************
     111         7712 :    FUNCTION xc_uses_norm_drho(xc_fun_section, lsd) RESULT(res)
     112              :       TYPE(section_vals_type), POINTER, INTENT(IN) :: xc_fun_section
     113              :       LOGICAL, INTENT(IN) :: lsd
     114              :       LOGICAL :: res
     115              : 
     116              :       TYPE(xc_rho_cflags_type)                           :: needs
     117              : 
     118              :       needs = xc_functionals_get_needs(xc_fun_section, &
     119              :                                        lsd=lsd, &
     120        15424 :                                        calc_potential=.FALSE.)
     121         7712 :       res = (needs%norm_drho .OR. needs%norm_drho_spin)
     122              : 
     123         7712 :    END FUNCTION xc_uses_norm_drho
     124              : 
     125              : ! **************************************************************************************************
     126              : !> \brief Exchange and Correlation functional calculations.
     127              : !>      depending on the selected functional_routine calls
     128              : !>      the correct routine
     129              : !> \param vxc_rho will contain the v_xc part that depend on rho
     130              : !>        (if one of the chosen xc functionals has it it is allocated and you
     131              : !>        are responsible for it)
     132              : !> \param vxc_tau will contain the kinetic tau part of v_xcthe functional
     133              : !>        (if one of the chosen xc functionals has it it is allocated and you
     134              : !>        are responsible for it)
     135              : !> \param rho_r the value of the density in the real space
     136              : !> \param rho_g value of the density in the g space (needs to be associated
     137              : !>        only for gradient corrections)
     138              : !> \param tau value of the kinetic density tau on the grid (can be null,
     139              : !>        used only with meta functionals)
     140              : !> \param exc the xc energy
     141              : !> \param xc_section parameters selecting the xc and the method used to
     142              : !>        calculate it
     143              : !> \param pw_pool the pool for the grids
     144              : !> \param compute_virial should the virial be computed... if so virial_xc must be present
     145              : !> \param virial_xc for calculating the GGA part of the stress
     146              : !> \param exc_r ...
     147              : !> \author fawzi
     148              : ! **************************************************************************************************
     149       222558 :    SUBROUTINE xc_vxc_pw_create1(vxc_rho, vxc_tau, rho_r, rho_g, tau, exc, xc_section, &
     150              :                                 pw_pool, compute_virial, virial_xc, exc_r)
     151              :       TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER             :: vxc_rho, vxc_tau
     152              :       TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: rho_r, tau
     153              :       TYPE(pw_c1d_gs_type), DIMENSION(:), POINTER :: rho_g
     154              :       REAL(KIND=dp), INTENT(out)                         :: exc
     155              :       TYPE(section_vals_type), POINTER                   :: xc_section
     156              :       TYPE(pw_pool_type), POINTER                        :: pw_pool
     157              :       LOGICAL, INTENT(IN)                                :: compute_virial
     158              :       REAL(KIND=dp), DIMENSION(3, 3), INTENT(OUT)        :: virial_xc
     159              :       TYPE(pw_r3d_rs_type), INTENT(INOUT), OPTIONAL           :: exc_r
     160              : 
     161              :       INTEGER                                            :: f_routine
     162              : 
     163       111279 :       CPASSERT(ASSOCIATED(rho_r))
     164       111279 :       CPASSERT(ASSOCIATED(xc_section))
     165       111279 :       CPASSERT(.NOT. ASSOCIATED(vxc_rho))
     166       111279 :       CPASSERT(.NOT. ASSOCIATED(vxc_tau))
     167              : 
     168       111279 :       virial_xc = 0.0_dp
     169              : 
     170              :       CALL section_vals_val_get(xc_section, "FUNCTIONAL_ROUTINE", &
     171       111279 :                                 i_val=f_routine)
     172       111279 :       SELECT CASE (f_routine)
     173              :       CASE (xc_default_f_routine)
     174              :          CALL xc_vxc_pw_create(vxc_rho=vxc_rho, vxc_tau=vxc_tau, tau=tau, exc_r=exc_r, &
     175              :                                rho_r=rho_r, rho_g=rho_g, exc=exc, xc_section=xc_section, &
     176       111279 :                                pw_pool=pw_pool, compute_virial=compute_virial, virial_xc=virial_xc)
     177              :       CASE (xc_debug_new_routine)
     178            0 :          CPASSERT(.NOT. PRESENT(exc_r))
     179              :          CALL xc_vxc_pw_create_debug(vxc_rho=vxc_rho, vxc_tau=vxc_tau, tau=tau, &
     180              :                                      rho_r=rho_r, rho_g=rho_g, exc=exc, xc_section=xc_section, &
     181            0 :                                      pw_pool=pw_pool)
     182              :       CASE (xc_test_lsd_f_routine)
     183            0 :          CPASSERT(.NOT. PRESENT(exc_r))
     184              :          CALL xc_vxc_pw_create_test_lsd(vxc_rho=vxc_rho, vxc_tau=vxc_tau, &
     185              :                                         tau=tau, rho_r=rho_r, rho_g=rho_g, exc=exc, &
     186       111279 :                                         xc_section=xc_section, pw_pool=pw_pool)
     187              :       CASE default
     188              :       END SELECT
     189              : 
     190       111279 :    END SUBROUTINE xc_vxc_pw_create1
     191              : 
     192              : ! **************************************************************************************************
     193              : !> \brief calculates vxc using lsd with rhoa=rhob=0.5*rho and compares
     194              : !>      with the lda result
     195              : !> \param vxc_rho will contain the v_xc part that depend on rho
     196              : !>        (if one of the chosen xc functionals has it it is allocated and you
     197              : !>        are responsible for it)
     198              : !> \param vxc_tau will contain the kinetic tau part of v_xc
     199              : !>        (if one of the chosen xc functionals has it it is allocated and you
     200              : !>        are responsible for it)
     201              : !> \param rho_r the value of the density in the real space
     202              : !> \param rho_g value of the density in the g space (needs to be associated
     203              : !>        only for gradient corrections)
     204              : !> \param tau value of the kinetic density tau on the grid (can be null,
     205              : !>        used only with meta functionals)
     206              : !> \param exc the xc energy
     207              : !> \param xc_section which functional to calculate, and how
     208              : !> \param pw_pool the pool for the grids
     209              : !> \author Fawzi Mohamed
     210              : !> \note
     211              : !>      for debugging only: leaks, and non parallel
     212              : ! **************************************************************************************************
     213            0 :    SUBROUTINE xc_vxc_pw_create_test_lsd(vxc_rho, vxc_tau, rho_r, rho_g, tau, &
     214              :                                         exc, xc_section, pw_pool)
     215              :       TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER             :: vxc_rho, vxc_tau
     216              :       TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER               :: rho_r, tau
     217              :       TYPE(pw_c1d_gs_type), DIMENSION(:), POINTER :: rho_g
     218              :       REAL(KIND=dp), INTENT(out)                         :: exc
     219              :       TYPE(section_vals_type), POINTER                   :: xc_section
     220              :       TYPE(pw_pool_type), POINTER                        :: pw_pool
     221              : 
     222              :       LOGICAL, PARAMETER                                 :: compute_virial = .FALSE.
     223              : 
     224              :       CHARACTER(len=default_path_length)                 :: filename
     225            0 :       INTEGER, DIMENSION(:), POINTER         :: split_desc
     226              :       INTEGER                                            :: i, ii, ispin, j, k, order
     227              :       INTEGER, DIMENSION(2, 3)                           :: bo
     228              :       REAL(kind=dp)                                      :: diff, exc2, maxdiff, tmp
     229              :       REAL(KIND=dp), DIMENSION(3, 3)                     :: virial_xc
     230            0 :       REAL(kind=dp), DIMENSION(:, :, :), POINTER         :: pot, pot2, pot3
     231              :       TYPE(cp_sll_xc_deriv_type), POINTER                :: deriv_iter
     232            0 :       TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER             :: vxc_rho2, vxc_tau2
     233            0 :       TYPE(pw_c1d_gs_type), DIMENSION(:), POINTER :: rho2_g
     234            0 :       TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER               ::  rho2_r, tau2
     235              :       TYPE(xc_derivative_set_type)                       :: dSet1, dSet2
     236              :       TYPE(xc_derivative_type), POINTER                  :: deriv, deriv2, deriv3
     237              :       TYPE(xc_rho_set_type)                              :: rho_set1, rho_set2
     238              : 
     239            0 :       NULLIFY (vxc_rho2, vxc_tau2, tau2, pot, pot3, pot3, &
     240            0 :                deriv, deriv2, deriv3, rho2_g)
     241              : 
     242            0 :       bo = rho_r(1)%pw_grid%bounds_local
     243              : 
     244            0 :       ALLOCATE (rho2_r(2))
     245            0 :       DO ispin = 1, 2
     246            0 :          CALL pw_pool%create_pw(rho2_r(ispin))
     247              :       END DO
     248            0 :       DO k = bo(1, 3), bo(2, 3)
     249            0 :          DO j = bo(1, 2), bo(2, 2)
     250            0 :             DO i = bo(1, 1), bo(2, 1)
     251            0 :                tmp = rho_r(1)%array(i, j, k)*0.5
     252            0 :                rho2_r(1)%array(i, j, k) = tmp
     253            0 :                rho2_r(2)%array(i, j, k) = tmp
     254              :             END DO
     255              :          END DO
     256              :       END DO
     257              : 
     258            0 :       IF (ASSOCIATED(tau)) THEN
     259            0 :          ALLOCATE (tau2(2))
     260            0 :          DO ispin = 1, 2
     261            0 :             CALL pw_pool%create_pw(tau2(ispin))
     262              :          END DO
     263              : 
     264            0 :          DO k = bo(1, 3), bo(2, 3)
     265            0 :             DO j = bo(1, 2), bo(2, 2)
     266            0 :                DO i = bo(1, 1), bo(2, 1)
     267            0 :                   tmp = tau(1)%array(i, j, k)*0.5
     268            0 :                   tau2(1)%array(i, j, k) = tmp
     269            0 :                   tau2(2)%array(i, j, k) = tmp
     270              :                END DO
     271              :             END DO
     272              :          END DO
     273              :       END IF
     274              : 
     275            0 :       PRINT *, "about to calculate xc (lda)"
     276              :       CALL xc_rho_set_and_dset_create(rho_r=rho_r, rho_g=rho_g, &
     277              :                                       tau=tau, xc_section=xc_section, &
     278              :                                       pw_pool=pw_pool, rho_set=rho_set1, &
     279              :                                       deriv_set=dSet1, deriv_order=1, &
     280            0 :                                       calc_potential=.FALSE.)
     281              :       CALL xc_vxc_pw_create(rho_r=rho_r, rho_g=rho_g, tau=tau, &
     282              :                             vxc_rho=vxc_rho, vxc_tau=vxc_tau, exc=exc, xc_section=xc_section, &
     283              :                             pw_pool=pw_pool, &
     284            0 :                             compute_virial=compute_virial, virial_xc=virial_xc)
     285            0 :       PRINT *, "did calculate xc (lda)"
     286            0 :       PRINT *, "about to calculate xc (lsd)"
     287              :       CALL xc_rho_set_and_dset_create(rho_set=rho_set2, deriv_set=dSet2, &
     288              :                                       rho_r=rho2_r, rho_g=rho2_g, tau=tau2, xc_section=xc_section, &
     289              :                                       pw_pool=pw_pool, deriv_order=1, &
     290            0 :                                       calc_potential=.FALSE.)
     291              :       CALL xc_vxc_pw_create(rho_r=rho2_r, rho_g=rho2_g, tau=tau2, &
     292              :                             vxc_rho=vxc_rho2, vxc_tau=vxc_tau2, exc=exc2, xc_section=xc_section, &
     293            0 :                             pw_pool=pw_pool, compute_virial=compute_virial, virial_xc=virial_xc)
     294            0 :       PRINT *, "did calculate xc (new)"
     295            0 :       PRINT *, "at (0,0,0) rho_r=", rho_r(1)%array(0, 0, 0), &
     296            0 :          "rho2_r(1)=", rho2_r(1)%array(0, 0, 0), &
     297            0 :          "rho2_r(2)=", rho2_r(2)%array(0, 0, 0), &
     298            0 :          "rho_r_sm=", rho_set1%rho(0, 0, 0), "rhoa2_r_sm=", rho_set2%rhoa(0, 0, 0), &
     299            0 :          "rhob2_r_sm=", rho_set2%rhob(0, 0, 0)
     300              :       OPEN (unit=120, file="rho.bindata", status="unknown", access='sequential', &
     301            0 :             form="unformatted", action="write")
     302            0 :       pot => rho_set1%rho
     303            0 :       WRITE (unit=120) pot(bo(1, 1):bo(2, 1), bo(1, 2):bo(2, 2), bo(2, 3))
     304            0 :       CLOSE (unit=120)
     305              :       OPEN (unit=120, file="rhoa.bindata", status="unknown", access='sequential', &
     306            0 :             form="unformatted", action="write")
     307            0 :       pot => rho_set2%rhoa
     308            0 :       WRITE (unit=120) pot(bo(1, 1):bo(2, 1), bo(1, 2):bo(2, 2), bo(2, 3))
     309            0 :       CLOSE (unit=120)
     310              :       OPEN (unit=120, file="rhob.bindata", status="unknown", access='sequential', &
     311            0 :             form="unformatted", action="write")
     312            0 :       pot => rho_set2%rhob
     313            0 :       WRITE (unit=120) pot(bo(1, 1):bo(2, 1), bo(1, 2):bo(2, 2), bo(2, 3))
     314            0 :       CLOSE (unit=120)
     315              :       OPEN (unit=120, file="ndrho.bindata", status="unknown", access='sequential', &
     316            0 :             form="unformatted", action="write")
     317            0 :       pot => rho_set1%norm_drho
     318            0 :       WRITE (unit=120) pot(:, :, bo(2, 3))
     319            0 :       CLOSE (unit=120)
     320              :       OPEN (unit=120, file="ndrhoa.bindata", status="unknown", access='sequential', &
     321            0 :             form="unformatted", action="write")
     322            0 :       pot => rho_set2%norm_drhoa
     323            0 :       WRITE (unit=120) pot(:, :, bo(2, 3))
     324            0 :       CLOSE (unit=120)
     325              :       OPEN (unit=120, file="ndrhob.bindata", status="unknown", access='sequential', &
     326            0 :             form="unformatted", action="write")
     327            0 :       pot => rho_set2%norm_drhob
     328            0 :       WRITE (unit=120) pot(:, :, bo(2, 3))
     329            0 :       CLOSE (unit=120)
     330            0 :       IF (rho_set1%has%tau) THEN
     331              :          OPEN (unit=120, file="tau.bindata", status="unknown", access='sequential', &
     332            0 :                form="unformatted", action="write")
     333            0 :          pot => rho_set1%tau
     334            0 :          WRITE (unit=120) pot(:, :, bo(2, 3))
     335            0 :          CLOSE (unit=120)
     336              :       END IF
     337            0 :       IF (rho_set2%has%tau_spin) THEN
     338              :          OPEN (unit=120, file="tau_a.bindata", status="unknown", access='sequential', &
     339            0 :                form="unformatted", action="write")
     340            0 :          pot => rho_set2%tau_a
     341            0 :          WRITE (unit=120) pot(:, :, bo(2, 3))
     342            0 :          CLOSE (unit=120)
     343              :          OPEN (unit=120, file="tau_v.bindata", status="unknown", access='sequential', &
     344            0 :                form="unformatted", action="write")
     345            0 :          pot => rho_set2%tau_b
     346            0 :          WRITE (unit=120) pot(:, :, bo(2, 3))
     347            0 :          CLOSE (unit=120)
     348              :       END IF
     349              :       OPEN (unit=120, file="vxc.bindata", status="unknown", access='sequential', &
     350            0 :             form="unformatted", action="write")
     351            0 :       pot => vxc_rho(1)%array
     352            0 :       WRITE (unit=120) pot(:, :, bo(2, 3))
     353            0 :       CLOSE (unit=120)
     354              :       OPEN (unit=120, file="vxc2.bindata", status="unknown", access='sequential', &
     355            0 :             form="unformatted", action="write")
     356            0 :       pot => vxc_rho2(1)%array
     357            0 :       WRITE (unit=120) pot(:, :, bo(2, 3))
     358            0 :       CLOSE (unit=120)
     359            0 :       IF (ASSOCIATED(vxc_tau)) THEN
     360              :          OPEN (unit=120, file="vxc_tau.bindata", status="unknown", access='sequential', &
     361            0 :                form="unformatted", action="write")
     362            0 :          pot => vxc_tau(1)%array
     363            0 :          WRITE (unit=120) pot(:, :, bo(2, 3))
     364            0 :          CLOSE (unit=120)
     365              :       END IF
     366            0 :       IF (ASSOCIATED(vxc_tau2)) THEN
     367              :          OPEN (unit=120, file="vxc_tau2_a.bindata", status="unknown", access='sequential', &
     368            0 :                form="unformatted", action="write")
     369            0 :          pot => vxc_tau2(1)%array
     370            0 :          WRITE (unit=120) pot(:, :, bo(2, 3))
     371            0 :          CLOSE (unit=120)
     372              :          OPEN (unit=120, file="vxc_tau2_b.bindata", status="unknown", access='sequential', &
     373            0 :                form="unformatted", action="write")
     374            0 :          pot => vxc_tau2(2)%array
     375            0 :          WRITE (unit=120) pot(:, :, bo(2, 3))
     376            0 :          CLOSE (unit=120)
     377              :       END IF
     378              : 
     379            0 :       PRINT *, "calc diff on vxc"
     380            0 :       maxDiff = 0.0_dp
     381            0 :       DO ispin = 1, 1
     382            0 :          ii = 0
     383            0 :          DO k = bo(1, 3), bo(2, 3)
     384            0 :             DO j = bo(1, 2), bo(2, 2)
     385            0 :                DO i = bo(1, 1), bo(2, 1)
     386            0 :                   ii = ii + 1
     387              :                   diff = ABS(vxc_rho(ispin)%array(i, j, k) - &
     388            0 :                              vxc_rho2(ispin)%array(i, j, k))
     389            0 :                   IF (ii == 1) THEN
     390            0 :                      PRINT *, "vxc", ispin, "=", vxc_rho(ispin)%array(i, j, k), &
     391            0 :                         "vs", vxc_rho2(ispin)%array(i, j, k), "diff=", diff
     392              :                   END IF
     393            0 :                   IF (maxDiff < diff) THEN
     394            0 :                      maxDiff = diff
     395            0 :                      PRINT *, "diff=", diff, " at ", i, ",", j, ",", k, &
     396            0 :                         " spin=", ispin, "rho=", rho_set1%rho(i, j, k), &
     397            0 :                         " ndrho=", rho_set1%norm_drho(i, j, k)
     398              :                   END IF
     399              :                END DO
     400              :             END DO
     401              :          END DO
     402              :       END DO
     403            0 :       PRINT *, "diff exc=", ABS(exc - exc2), "diff vxc=", maxdiff
     404              :       ! CPASSERT(maxdiff<5.e-11)
     405              :       ! CPASSERT(ABS(exc-exc2)<1.e-14)
     406              : 
     407            0 :       IF (ASSOCIATED(vxc_tau)) THEN
     408            0 :          PRINT *, "calc diff on vxc_tau"
     409            0 :          maxDiff = 0.0_dp
     410            0 :          DO ispin = 1, 1
     411            0 :             ii = 0
     412            0 :             DO k = bo(1, 3), bo(2, 3)
     413            0 :                DO j = bo(1, 2), bo(2, 2)
     414            0 :                   DO i = bo(1, 1), bo(2, 1)
     415            0 :                      ii = ii + 1
     416              :                      diff = ABS(vxc_tau(ispin)%array(i, j, k) - &
     417            0 :                                 vxc_tau2(ispin)%array(i, j, k))
     418            0 :                      IF (ii == 1) THEN
     419            0 :                         PRINT *, "vxc_tau", ispin, "=", vxc_tau(ispin)%array(i, j, k), &
     420            0 :                            "vs", vxc_tau2(ispin)%array(i, j, k), "diff=", diff
     421              :                      END IF
     422            0 :                      IF (maxDiff < diff) THEN
     423            0 :                         maxDiff = diff
     424            0 :                         PRINT *, "diff=", diff, " at ", i, ",", j, ",", k, &
     425            0 :                            " spin=", ispin, "rho=", rho_set1%rho(i, j, k), &
     426            0 :                            " ndrho=", rho_set1%norm_drho(i, j, k)
     427              :                      END IF
     428              :                   END DO
     429              :                END DO
     430              :             END DO
     431              :          END DO
     432            0 :          PRINT *, "diff exc=", ABS(exc - exc2), "diff vxc_tau=", maxdiff
     433              :       END IF
     434            0 :       deriv_iter => dSet1%derivs
     435            0 :       DO WHILE (cp_sll_xc_deriv_next(deriv_iter, el_att=deriv))
     436              :          CALL xc_derivative_get(deriv, order=order, &
     437            0 :                                 split_desc=split_desc, deriv_data=pot)
     438            0 :          SELECT CASE (order)
     439              :          CASE (0)
     440            0 :             filename = "e_0.bindata"
     441            0 :             deriv2 => xc_dset_get_derivative(dSet2, [INTEGER::])
     442              :          CASE (1)
     443            0 :             filename = "e_"//TRIM(id_to_desc(split_desc(1)))//".bindata"
     444            0 :             IF (split_desc(1) == deriv_rho) THEN
     445            0 :                deriv2 => xc_dset_get_derivative(dSet2, [deriv_rhoa])
     446            0 :             ELSEIF (split_desc(1) == deriv_tau) THEN
     447            0 :                deriv2 => xc_dset_get_derivative(dSet2, [deriv_tau_a])
     448            0 :             ELSEIF (split_desc(1) == deriv_norm_drho) THEN
     449            0 :                deriv2 => xc_dset_get_derivative(dSet2, [deriv_norm_drhoa])
     450            0 :                deriv3 => xc_dset_get_derivative(dSet2, [deriv_norm_drho])
     451            0 :                IF (ASSOCIATED(deriv3)) THEN
     452            0 :                   IF (ASSOCIATED(deriv2)) THEN
     453              :                      CALL xc_derivative_get(deriv2, &
     454            0 :                                             deriv_data=pot2)
     455              :                      CALL xc_derivative_get(deriv3, &
     456            0 :                                             deriv_data=pot3)
     457            0 :                      pot2 = pot2 + pot3
     458              :                   ELSE
     459              :                      deriv2 => deriv3
     460              :                   END IF
     461            0 :                   NULLIFY (deriv3, pot2, pot3)
     462              :                END IF
     463              :             ELSE
     464            0 :                CPABORT("Unknown derivative variable")
     465              :             END IF
     466              :          CASE default
     467            0 :             CPABORT("Unsupported derivative order")
     468              :          END SELECT
     469              :          CALL xc_derivative_get(deriv2, &
     470            0 :                                 deriv_data=pot2)
     471            0 :          PRINT *, "checking ", filename
     472            0 :          maxDiff = 0.0_dp
     473            0 :          DO k = bo(1, 3), bo(2, 3)
     474            0 :             DO j = bo(1, 2), bo(2, 2)
     475            0 :                DO i = bo(1, 1), bo(2, 1)
     476            0 :                   diff = ABS(pot(i, j, k) - pot2(i, j, k))
     477            0 :                   IF (maxDiff < diff) THEN
     478            0 :                      maxDiff = diff
     479            0 :                      PRINT *, "ediff(", i, j, k, ")=", maxDiff, &
     480            0 :                         "rho=", rho_set1%rho(i, j, k), &
     481            0 :                         "ndrho=", rho_set1%norm_drho(i, j, k)
     482              :                   END IF
     483              :                END DO
     484              :             END DO
     485              :          END DO
     486            0 :          PRINT *, "maxdiff ", filename, "=", maxDiff
     487              :          OPEN (unit=120, file=TRIM(filename), status="unknown", &
     488              :                access='sequential', &
     489            0 :                form="unformatted")
     490            0 :          WRITE (unit=120) pot(:, :, bo(2, 3))
     491            0 :          CLOSE (unit=120)
     492              :       END DO
     493            0 :       deriv_iter => dSet2%derivs
     494            0 :       DO WHILE (cp_sll_xc_deriv_next(deriv_iter, el_att=deriv))
     495              :          CALL xc_derivative_get(deriv, order=order, &
     496            0 :                                 split_desc=split_desc, deriv_data=pot)
     497            0 :          SELECT CASE (order)
     498              :          CASE (0)
     499            0 :             filename = "e_0-2.bindata"
     500              :          CASE (1)
     501            0 :             filename = "e_"//TRIM(id_to_desc(split_desc(1)))//"-2.bindata"
     502              :          CASE default
     503            0 :             CPABORT("Unsupported derivative order")
     504              :          END SELECT
     505              :          OPEN (unit=120, file=TRIM(filename), status="unknown", &
     506              :                access='sequential', &
     507            0 :                form="unformatted")
     508            0 :          WRITE (unit=120) pot(:, :, bo(2, 3))
     509            0 :          CLOSE (unit=120)
     510              :       END DO
     511            0 :       CALL xc_rho_set_release(rho_set1)
     512            0 :       CALL xc_rho_set_release(rho_set2)
     513            0 :       CALL xc_dset_release(dSet2)
     514            0 :       CALL xc_dset_release(dSet1)
     515            0 :       DO ispin = 1, 2
     516            0 :          CALL pw_pool%give_back_pw(rho2_r(ispin))
     517            0 :          CALL pw_pool%give_back_pw(vxc_rho2(ispin))
     518            0 :          IF (ASSOCIATED(vxc_tau2)) THEN
     519            0 :             CALL pw_pool%give_back_pw(vxc_tau2(ispin))
     520              :          END IF
     521              :       END DO
     522            0 :       DEALLOCATE (vxc_rho2, rho2_r, rho2_g)
     523            0 :       IF (ASSOCIATED(vxc_tau2)) THEN
     524            0 :          DEALLOCATE (vxc_tau2)
     525              :       END IF
     526              : 
     527            0 :    END SUBROUTINE xc_vxc_pw_create_test_lsd
     528              : 
     529              : ! **************************************************************************************************
     530              : !> \brief calculates vxc outputting the yz plane of rho, and of the various components
     531              : !>      of the the derivatives and of vxc
     532              : !> \param vxc_rho will contain the v_xc part that depend on rho
     533              : !>        (if one of the chosen xc functionals has it it is allocated and you
     534              : !>        are responsible for it)
     535              : !> \param vxc_tau will contain the kinetic tau part of v_xc
     536              : !>        (if one of the chosen xc functionals has it it is allocated and you
     537              : !>        are responsible for it)
     538              : !> \param rho_r the value of the density in the real space
     539              : !> \param rho_g value of the density in the g space (needs to be associated
     540              : !>        only for gradient corrections)
     541              : !> \param tau value of the kinetic density tau on the grid (can be null,
     542              : !>        used only with meta functionals)
     543              : !> \param exc the xc energy
     544              : !> \param xc_section which functional should be used, and how to do it
     545              : !> \param pw_pool the pool for the grids
     546              : !> \author Fawzi Mohamed
     547              : !> \note
     548              : !>      for debugging only.
     549              : ! **************************************************************************************************
     550            0 :    SUBROUTINE xc_vxc_pw_create_debug(vxc_rho, vxc_tau, rho_r, rho_g, tau, exc, &
     551              :                                      xc_section, pw_pool)
     552              :       TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER             :: vxc_rho, vxc_tau
     553              :       TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER               :: rho_r, tau
     554              :       TYPE(pw_c1d_gs_type), DIMENSION(:), POINTER :: rho_g
     555              :       REAL(KIND=dp), INTENT(out)                         :: exc
     556              :       TYPE(section_vals_type), POINTER                   :: xc_section
     557              :       TYPE(pw_pool_type), POINTER                        :: pw_pool
     558              : 
     559              :       LOGICAL, PARAMETER                                 :: compute_virial = .FALSE.
     560              : 
     561              :       CHARACTER(len=default_path_length)                 :: filename
     562            0 :       INTEGER, DIMENSION(:), POINTER         :: split_desc
     563              :       INTEGER                                            :: i, ispin, j, k, order
     564              :       INTEGER, DIMENSION(2, 3)                           :: bo
     565              :       REAL(KIND=dp), DIMENSION(3, 3)                     :: virial_xc
     566            0 :       REAL(kind=dp), DIMENSION(:, :, :), POINTER         :: pot
     567              :       TYPE(cp_logger_type), POINTER                      :: logger
     568              :       TYPE(cp_sll_xc_deriv_type), POINTER                :: deriv_iter
     569              :       TYPE(xc_derivative_set_type)                       :: dSet1
     570              :       TYPE(xc_derivative_type), POINTER                  :: deriv
     571              :       TYPE(xc_rho_set_type)                              :: rho_set1
     572              : 
     573            0 :       NULLIFY (pot, deriv)
     574            0 :       logger => cp_get_default_logger()
     575              : 
     576            0 :       bo = rho_r(1)%pw_grid%bounds_local
     577              : 
     578              :       CALL xc_rho_set_and_dset_create(rho_r=rho_r, rho_g=rho_g, &
     579              :                                       tau=tau, xc_section=xc_section, &
     580              :                                       pw_pool=pw_pool, rho_set=rho_set1, &
     581              :                                       deriv_set=dSet1, deriv_order=1, &
     582            0 :                                       calc_potential=.FALSE.)
     583              : 
     584              :       ! outputs 0,:,: plane
     585            0 :       IF (bo(1, 1) <= 0 .AND. 0 <= bo(2, 1)) THEN
     586            0 :          IF (rho_set1%has%rho_spin) THEN
     587              :             OPEN (unit=120, file="rhoa.bindata", status="unknown", access='sequential', &
     588            0 :                   form="unformatted", action="write")
     589            0 :             pot => rho_set1%rhoa
     590            0 :             WRITE (unit=120) pot(0, :, :)
     591            0 :             CLOSE (unit=120)
     592              :             OPEN (unit=120, file="rhob.bindata", status="unknown", access='sequential', &
     593            0 :                   form="unformatted", action="write")
     594            0 :             pot => rho_set1%rhob
     595            0 :             WRITE (unit=120) pot(0, :, :)
     596            0 :             CLOSE (unit=120)
     597              :          END IF
     598            0 :          IF (rho_set1%has%norm_drho) THEN
     599              :             OPEN (unit=120, file="ndrho.bindata", status="unknown", access='sequential', &
     600            0 :                   form="unformatted", action="write")
     601            0 :             pot => rho_set1%norm_drho
     602            0 :             WRITE (unit=120) pot(0, :, :)
     603            0 :             CLOSE (unit=120)
     604              :          END IF
     605            0 :          IF (rho_set1%has%norm_drho_spin) THEN
     606              :             OPEN (unit=120, file="ndrhoa.bindata", status="unknown", access='sequential', &
     607            0 :                   form="unformatted", action="write")
     608            0 :             pot => rho_set1%norm_drhoa
     609            0 :             WRITE (unit=120) pot(0, :, :)
     610            0 :             CLOSE (unit=120)
     611              :             OPEN (unit=120, file="ndrhob.bindata", status="unknown", access='sequential', &
     612            0 :                   form="unformatted", action="write")
     613            0 :             pot => rho_set1%norm_drhob
     614            0 :             WRITE (unit=120) pot(0, :, :)
     615            0 :             CLOSE (unit=120)
     616              :          END IF
     617            0 :          IF (rho_set1%has%rho) THEN
     618              :             OPEN (unit=120, file="rho.bindata", status="unknown", access='sequential', &
     619            0 :                   form="unformatted", action="write")
     620            0 :             pot => rho_set1%rho
     621            0 :             WRITE (unit=120) pot(0, :, :)
     622            0 :             CLOSE (unit=120)
     623              :          END IF
     624            0 :          IF (rho_set1%has%tau) THEN
     625              :             OPEN (unit=120, file="tau.bindata", status="unknown", access='sequential', &
     626            0 :                   form="unformatted", action="write")
     627            0 :             pot => rho_set1%tau
     628            0 :             WRITE (unit=120) pot(0, :, :)
     629            0 :             CLOSE (unit=120)
     630              :          END IF
     631            0 :          IF (rho_set1%has%tau_spin) THEN
     632              :             OPEN (unit=120, file="tau_a.bindata", status="unknown", access='sequential', &
     633            0 :                   form="unformatted", action="write")
     634            0 :             pot => rho_set1%tau_a
     635            0 :             WRITE (unit=120) pot(0, :, :)
     636            0 :             CLOSE (unit=120)
     637              :             OPEN (unit=120, file="tau_b.bindata", status="unknown", access='sequential', &
     638            0 :                   form="unformatted", action="write")
     639            0 :             pot => rho_set1%tau_b
     640            0 :             WRITE (unit=120) pot(0, :, :)
     641            0 :             CLOSE (unit=120)
     642              :          END IF
     643              : 
     644            0 :          deriv_iter => dSet1%derivs
     645            0 :          DO WHILE (cp_sll_xc_deriv_next(deriv_iter, el_att=deriv))
     646              :             CALL xc_derivative_get(deriv, order=order, &
     647            0 :                                    split_desc=split_desc, deriv_data=pot)
     648            0 :             SELECT CASE (order)
     649              :             CASE (0)
     650            0 :                filename = "e_0.bindata"
     651              :             CASE (1)
     652            0 :                filename = "e_"//TRIM(id_to_desc(split_desc(1)))//".bindata"
     653              :             CASE default
     654            0 :                CPABORT("Unsupported derivative order")
     655              :             END SELECT
     656              :             OPEN (unit=120, file=TRIM(filename), status="unknown", &
     657              :                   access='sequential', &
     658            0 :                   form="unformatted")
     659            0 :             WRITE (unit=120) pot(0, :, :)
     660            0 :             CLOSE (unit=120)
     661              :          END DO
     662              :       END IF
     663              : 
     664              :       CALL xc_vxc_pw_create(vxc_rho=vxc_rho, vxc_tau=vxc_tau, &
     665              :                             rho_r=rho_r, rho_g=rho_g, tau=tau, &
     666              :                             exc=exc, xc_section=xc_section, &
     667              :                             pw_pool=pw_pool, &
     668            0 :                             compute_virial=compute_virial, virial_xc=virial_xc)
     669              : 
     670              :       ! outputs 0,:,: plane
     671            0 :       IF (bo(1, 1) <= 0 .AND. 0 <= bo(2, 1)) THEN
     672            0 :          IF (ASSOCIATED(vxc_rho)) THEN
     673            0 :             DO ispin = 1, SIZE(vxc_rho)
     674            0 :                WRITE (filename, "('vxc-',i1,'.bindata')") ispin
     675              :                OPEN (unit=120, file=filename, status="unknown", access='sequential', &
     676            0 :                      form="unformatted", action="write")
     677            0 :                pot => vxc_rho(ispin)%array
     678            0 :                WRITE (unit=120) pot(0, :, :)
     679            0 :                CLOSE (unit=120)
     680              : 
     681            0 :                pot => vxc_rho(ispin)%array
     682            0 :                DO k = bo(1, 3), bo(2, 3)
     683            0 :                   DO j = bo(1, 2), bo(2, 2)
     684            0 :                      DO i = bo(1, 1), bo(2, 1)
     685            0 :                         IF (ABS(pot(i, j, k)) > 10.0_dp) THEN
     686              :                            WRITE (cp_logger_get_default_unit_nr(logger), &
     687              :                                   "(' vxc_',i1,'(',i6,',',i6,',',i6,')=',e11.4)", &
     688            0 :                                   advance="no") ispin, i, j, k, pot(i, j, k)
     689            0 :                            IF (rho_set1%has%rho_spin) THEN
     690              :                               WRITE (cp_logger_get_default_unit_nr(logger), &
     691              :                                      "(' rho=(',e11.4,',',e11.4,')')", advance="no") &
     692            0 :                                  rho_set1%rhoa(i, j, k), rho_set1%rhob(i, j, k)
     693            0 :                            ELSE IF (rho_set1%has%rho) THEN
     694              :                               WRITE (cp_logger_get_default_unit_nr(logger), &
     695            0 :                                      "(' rho=',e11.4)", advance="no") rho_set1%rho(i, j, k)
     696              :                            END IF
     697            0 :                            IF (rho_set1%has%norm_drho_spin) THEN
     698              :                               WRITE (cp_logger_get_default_unit_nr(logger), &
     699              :                                      "(' ndrho=(',e11.4,',',e11.4,')')", advance="no") &
     700            0 :                                  rho_set1%norm_drhoa(i, j, k), &
     701            0 :                                  rho_set1%norm_drhob(i, j, k)
     702            0 :                            ELSE IF (rho_set1%has%norm_drho) THEN
     703              :                               WRITE (cp_logger_get_default_unit_nr(logger), &
     704            0 :                                      "(' ndrho=',e11.4)", advance="no") rho_set1%norm_drho(i, j, k)
     705              :                            END IF
     706            0 :                            IF (rho_set1%has%tau_spin) THEN
     707              :                               WRITE (cp_logger_get_default_unit_nr(logger), &
     708              :                                      "(' tau=(',e11.4,',',e11.4,')')", advance="no") &
     709            0 :                                  rho_set1%tau_a(i, j, k), &
     710            0 :                                  rho_set1%tau_b(i, j, k)
     711            0 :                            ELSE IF (rho_set1%has%tau) THEN
     712              :                               WRITE (cp_logger_get_default_unit_nr(logger), &
     713            0 :                                      "(' tau=',e11.4)", advance="no") rho_set1%tau(i, j, k)
     714              :                            END IF
     715              : 
     716            0 :                            deriv_iter => dSet1%derivs
     717            0 :                            DO WHILE (cp_sll_xc_deriv_next(deriv_iter, el_att=deriv))
     718              :                               CALL xc_derivative_get(deriv, order=order, &
     719            0 :                                                      split_desc=split_desc, deriv_data=pot)
     720            0 :                               SELECT CASE (order)
     721              :                               CASE (0)
     722            0 :                                  filename = " e_0"
     723              :                               CASE (1)
     724            0 :                                  filename = " e_"//TRIM(id_to_desc(split_desc(1)))
     725              :                               CASE default
     726            0 :                                  CPABORT("Unsupported derivative order")
     727              :                               END SELECT
     728              :                               WRITE (unit=cp_logger_get_default_unit_nr(logger), &
     729              :                                      fmt="(a,'=',e11.4)", advance="no") &
     730            0 :                                  TRIM(filename), pot(i, j, k)
     731              :                            END DO
     732              : 
     733              :                            WRITE (cp_logger_get_default_unit_nr(logger), &
     734            0 :                                   "()")
     735              :                         END IF
     736              :                      END DO
     737              :                   END DO
     738              :                END DO
     739              :             END DO
     740              :          END IF
     741            0 :          IF (ASSOCIATED(vxc_tau)) THEN
     742            0 :             DO ispin = 1, SIZE(vxc_tau)
     743            0 :                WRITE (filename, "('vxc_tau_',i1,'.bindata')") ispin
     744              :                OPEN (unit=120, file=filename, status="unknown", access='sequential', &
     745            0 :                      form="unformatted", action="write")
     746            0 :                pot => vxc_tau(ispin)%array
     747            0 :                WRITE (unit=120) pot(0, :, :)
     748            0 :                CLOSE (unit=120)
     749              : 
     750            0 :                pot => vxc_tau(ispin)%array
     751            0 :                DO k = bo(1, 3), bo(2, 3)
     752            0 :                   DO j = bo(1, 2), bo(2, 2)
     753            0 :                      DO i = bo(1, 1), bo(2, 1)
     754            0 :                         IF (ABS(pot(i, j, k)) > 10.0_dp) THEN
     755              :                            WRITE (cp_logger_get_default_unit_nr(logger), &
     756              :                                   "('vxc_tau_',i1,'(',i6,',',i6,',',i6,')=',e11.4)", &
     757            0 :                                   advance="no") ispin, i, j, k, pot(i, j, k)
     758            0 :                            IF (rho_set1%has%rho_spin) THEN
     759              :                               WRITE (cp_logger_get_default_unit_nr(logger), &
     760              :                                      "(' rho=(',e11.4,',',e11.4,')')", advance="no") &
     761            0 :                                  rho_set1%rhoa(i, j, k), rho_set1%rhob(i, j, k)
     762            0 :                            ELSE IF (rho_set1%has%rho) THEN
     763              :                               WRITE (cp_logger_get_default_unit_nr(logger), &
     764            0 :                                      "(' rho=',e11.4)", advance="no") rho_set1%rho(i, j, k)
     765              :                            END IF
     766            0 :                            IF (rho_set1%has%norm_drho_spin) THEN
     767              :                               WRITE (cp_logger_get_default_unit_nr(logger), &
     768              :                                      "(' ndrho=(',e11.4,',',e11.4,')')", advance="no") &
     769            0 :                                  rho_set1%norm_drhoa(i, j, k), &
     770            0 :                                  rho_set1%norm_drhob(i, j, k)
     771            0 :                            ELSE IF (rho_set1%has%norm_drho) THEN
     772              :                               WRITE (cp_logger_get_default_unit_nr(logger), &
     773            0 :                                      "(' ndrho=',e11.4)", advance="no") rho_set1%norm_drho(i, j, k)
     774              :                            END IF
     775            0 :                            IF (rho_set1%has%tau_spin) THEN
     776              :                               WRITE (cp_logger_get_default_unit_nr(logger), &
     777              :                                      "(' tau=(',e11.4,',',e11.4,')')", advance="no") &
     778            0 :                                  rho_set1%tau_a(i, j, k), &
     779            0 :                                  rho_set1%tau_b(i, j, k)
     780            0 :                            ELSE IF (rho_set1%has%tau) THEN
     781              :                               WRITE (cp_logger_get_default_unit_nr(logger), &
     782            0 :                                      "(' tau=',e11.4)", advance="no") rho_set1%tau(i, j, k)
     783              :                            END IF
     784              : 
     785            0 :                            deriv_iter => dSet1%derivs
     786            0 :                            DO WHILE (cp_sll_xc_deriv_next(deriv_iter, el_att=deriv))
     787              :                               CALL xc_derivative_get(deriv, order=order, &
     788            0 :                                                      split_desc=split_desc, deriv_data=pot)
     789            0 :                               SELECT CASE (order)
     790              :                               CASE (0)
     791            0 :                                  filename = " e_0"
     792              :                               CASE (1)
     793            0 :                                  filename = " e_"//TRIM(id_to_desc(split_desc(1)))
     794              :                               CASE default
     795            0 :                                  CPABORT("Unsupported derivative order")
     796              :                               END SELECT
     797              :                               WRITE (unit=cp_logger_get_default_unit_nr(logger), &
     798              :                                      fmt="(a,'=',e11.4)", advance="no") &
     799            0 :                                  TRIM(filename), pot(i, j, k)
     800              :                            END DO
     801              : 
     802            0 :                            WRITE (cp_logger_get_default_unit_nr(logger), "()")
     803              :                         END IF
     804              :                      END DO
     805              :                   END DO
     806              :                END DO
     807              :             END DO
     808              :          END IF
     809              :       END IF
     810              : 
     811            0 :       CALL xc_dset_release(dSet1)
     812            0 :       CALL xc_rho_set_release(rho_set1)
     813            0 :    END SUBROUTINE xc_vxc_pw_create_debug
     814              : 
     815              : ! **************************************************************************************************
     816              : !> \brief creates a xc_rho_set and a derivative set containing the derivatives
     817              : !>      of the functionals with the given deriv_order.
     818              : !> \param rho_set will contain the rho set
     819              : !> \param deriv_set will contain the derivatives
     820              : !> \param deriv_order the order of the requested derivatives. If positive
     821              : !>        0:deriv_order are calculated, if negative only -deriv_order is
     822              : !>        guaranteed to be valid. Orders not requested might be present,
     823              : !>        but might contain garbage.
     824              : !> \param rho_r the value of the density in the real space
     825              : !> \param rho_g value of the density in the g space (can be null, used only
     826              : !>        without smoothing of rho or deriv)
     827              : !> \param tau value of the kinetic density tau on the grid (can be null,
     828              : !>        used only with meta functionals)
     829              : !> \param xc_section the section describing the functional to use
     830              : !> \param pw_pool the pool for the grids
     831              : !> \param calc_potential if the basic components of the arguments
     832              : !>        should be kept in rho set (a basic component is for example drho
     833              : !>        when with lda a functional needs norm_drho)
     834              : !> \author fawzi
     835              : !> \note
     836              : !>      if any of the functionals is gradient corrected the full gradient is
     837              : !>      added to the rho set
     838              : ! **************************************************************************************************
     839       272950 :    SUBROUTINE xc_rho_set_and_dset_create(rho_set, deriv_set, deriv_order, &
     840              :                                          rho_r, rho_g, tau, xc_section, pw_pool, &
     841              :                                          calc_potential)
     842              : 
     843              :       TYPE(xc_rho_set_type)                              :: rho_set
     844              :       TYPE(xc_derivative_set_type)                       :: deriv_set
     845              :       INTEGER, INTENT(in)                                :: deriv_order
     846              :       TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER               :: rho_r, tau
     847              :       TYPE(pw_c1d_gs_type), DIMENSION(:), POINTER :: rho_g
     848              :       TYPE(section_vals_type), POINTER                   :: xc_section
     849              :       TYPE(pw_pool_type), POINTER                        :: pw_pool
     850              :       LOGICAL, INTENT(in)                                :: calc_potential
     851              : 
     852              :       CHARACTER(len=*), PARAMETER :: routineN = 'xc_rho_set_and_dset_create'
     853              : 
     854              :       INTEGER                                            :: handle, nspins
     855              :       LOGICAL                                            :: lsd
     856              :       TYPE(section_vals_type), POINTER                   :: xc_fun_sections
     857              : 
     858       136475 :       CALL timeset(routineN, handle)
     859              : 
     860       136475 :       CPASSERT(ASSOCIATED(pw_pool))
     861              : 
     862       136475 :       nspins = SIZE(rho_r)
     863       136475 :       lsd = (nspins /= 1)
     864              : 
     865       136475 :       xc_fun_sections => section_vals_get_subs_vals(xc_section, "XC_FUNCTIONAL")
     866              : 
     867              :       ! Create deriv_set object
     868       136475 :       CALL xc_dset_create(deriv_set, pw_pool)
     869              : 
     870              :       ! Create objects for density related stuff
     871              :       CALL xc_rho_set_create(rho_set, &
     872              :                              rho_r(1)%pw_grid%bounds_local, &
     873              :                              rho_cutoff=section_get_rval(xc_section, "density_cutoff"), &
     874              :                              drho_cutoff=section_get_rval(xc_section, "gradient_cutoff"), &
     875       136475 :                              tau_cutoff=section_get_rval(xc_section, "tau_cutoff"))
     876              : 
     877              :       ! Calculate density stuff, for example the gradient of rho, according to the functional needs
     878              :       CALL xc_rho_set_update(rho_set, rho_r, rho_g, tau, &
     879              :                              xc_functionals_get_needs(xc_fun_sections, lsd, calc_potential), &
     880              :                              section_get_ival(xc_section, "XC_GRID%XC_DERIV"), &
     881              :                              section_get_ival(xc_section, "XC_GRID%XC_SMOOTH_RHO"), &
     882       136475 :                              pw_pool)
     883              : 
     884              :       ! Calculate values of the functional on the grid
     885              :       CALL xc_functionals_eval(xc_fun_sections, &
     886              :                                lsd=lsd, &
     887              :                                rho_set=rho_set, &
     888              :                                deriv_set=deriv_set, &
     889       136475 :                                deriv_order=deriv_order)
     890              : 
     891       136475 :       CALL divide_by_norm_drho(deriv_set, rho_set, lsd)
     892              : 
     893       136475 :       CALL timestop(handle)
     894              : 
     895       136475 :    END SUBROUTINE xc_rho_set_and_dset_create
     896              : 
     897              : ! **************************************************************************************************
     898              : !> \brief smooths the cutoff on rho with a function smoothderiv_rho that is 0
     899              : !>      for rho<rho_cutoff and 1 for rho>rho_cutoff*rho_smooth_cutoff_range:
     900              : !>      E= integral e_0*smoothderiv_rho => dE/d...= de/d... * smooth,
     901              : !>      dE/drho = de/drho * smooth + e_0 * dsmooth/drho
     902              : !> \param pot the potential to smooth
     903              : !> \param rho , rhoa,rhob: the value of the density (used to apply the cutoff)
     904              : !> \param rhoa ...
     905              : !> \param rhob ...
     906              : !> \param rho_cutoff the value at whch the cutoff function must go to 0
     907              : !> \param rho_smooth_cutoff_range range of the smoothing
     908              : !> \param e_0 value of e_0, if given it is assumed that pot is the derivative
     909              : !>        wrt. to rho, and needs the dsmooth*e_0 contribution
     910              : !> \param e_0_scale_factor ...
     911              : !> \author Fawzi Mohamed
     912              : ! **************************************************************************************************
     913       259537 :    SUBROUTINE smooth_cutoff(pot, rho, rhoa, rhob, rho_cutoff, &
     914              :                             rho_smooth_cutoff_range, e_0, e_0_scale_factor)
     915              :       REAL(kind=dp), DIMENSION(:, :, :), INTENT(IN), &
     916              :          POINTER                                         :: pot, rho, rhoa, rhob
     917              :       REAL(kind=dp), INTENT(in)                          :: rho_cutoff, rho_smooth_cutoff_range
     918              :       REAL(kind=dp), DIMENSION(:, :, :), OPTIONAL, &
     919              :          POINTER                                         :: e_0
     920              :       REAL(kind=dp), INTENT(in), OPTIONAL                :: e_0_scale_factor
     921              : 
     922              :       INTEGER                                            :: i, j, k
     923              :       INTEGER, DIMENSION(2, 3)                           :: bo
     924              :       REAL(kind=dp) :: my_e_0_scale_factor, my_rho, my_rho_n, my_rho_n2, rho_smooth_cutoff, &
     925              :                        rho_smooth_cutoff_2, rho_smooth_cutoff_range_2
     926              : 
     927       259537 :       CPASSERT(ASSOCIATED(pot))
     928      1038148 :       bo(1, :) = LBOUND(pot)
     929      1038148 :       bo(2, :) = UBOUND(pot)
     930       259537 :       my_e_0_scale_factor = 1.0_dp
     931       259537 :       IF (PRESENT(e_0_scale_factor)) my_e_0_scale_factor = e_0_scale_factor
     932       259537 :       rho_smooth_cutoff = rho_cutoff*rho_smooth_cutoff_range
     933       259537 :       rho_smooth_cutoff_2 = (rho_cutoff + rho_smooth_cutoff)/2
     934       259537 :       rho_smooth_cutoff_range_2 = rho_smooth_cutoff_2 - rho_cutoff
     935              : 
     936       259537 :       IF (rho_smooth_cutoff_range > 0.0_dp) THEN
     937            2 :          IF (PRESENT(e_0)) THEN
     938            0 :             CPASSERT(ASSOCIATED(e_0))
     939            0 :             IF (ASSOCIATED(rho)) THEN
     940              : !$OMP PARALLEL DO DEFAULT(NONE) &
     941              : !$OMP             SHARED(bo,e_0,pot,rho,rho_cutoff,rho_smooth_cutoff,rho_smooth_cutoff_2, &
     942              : !$OMP                    rho_smooth_cutoff_range_2,my_e_0_scale_factor) &
     943              : !$OMP             PRIVATE(k,j,i,my_rho,my_rho_n,my_rho_n2) &
     944            0 : !$OMP             COLLAPSE(3)
     945              :                DO k = bo(1, 3), bo(2, 3)
     946              :                   DO j = bo(1, 2), bo(2, 2)
     947              :                      DO i = bo(1, 1), bo(2, 1)
     948              :                         my_rho = rho(i, j, k)
     949              :                         IF (my_rho < rho_smooth_cutoff) THEN
     950              :                            IF (my_rho < rho_cutoff) THEN
     951              :                               pot(i, j, k) = 0.0_dp
     952              :                            ELSEIF (my_rho < rho_smooth_cutoff_2) THEN
     953              :                               my_rho_n = (my_rho - rho_cutoff)/rho_smooth_cutoff_range_2
     954              :                               my_rho_n2 = my_rho_n*my_rho_n
     955              :                               pot(i, j, k) = pot(i, j, k)* &
     956              :                                              my_rho_n2*(my_rho_n - 0.5_dp*my_rho_n2) + &
     957              :                                              my_e_0_scale_factor*e_0(i, j, k)* &
     958              :                                              my_rho_n2*(3.0_dp - 2.0_dp*my_rho_n) &
     959              :                                              /rho_smooth_cutoff_range_2
     960              :                            ELSE
     961              :                               my_rho_n = 2.0_dp - (my_rho - rho_cutoff)/rho_smooth_cutoff_range_2
     962              :                               my_rho_n2 = my_rho_n*my_rho_n
     963              :                               pot(i, j, k) = pot(i, j, k)* &
     964              :                                              (1.0_dp - my_rho_n2*(my_rho_n - 0.5_dp*my_rho_n2)) &
     965              :                                              + my_e_0_scale_factor*e_0(i, j, k)* &
     966              :                                              my_rho_n2*(3.0_dp - 2.0_dp*my_rho_n) &
     967              :                                              /rho_smooth_cutoff_range_2
     968              :                            END IF
     969              :                         END IF
     970              :                      END DO
     971              :                   END DO
     972              :                END DO
     973              : !$OMP END PARALLEL DO
     974              :             ELSE
     975              : !$OMP PARALLEL DO DEFAULT(NONE) &
     976              : !$OMP             SHARED(bo,pot,e_0,rhoa,rhob,rho_cutoff,rho_smooth_cutoff,rho_smooth_cutoff_2, &
     977              : !$OMP                    rho_smooth_cutoff_range_2,my_e_0_scale_factor) &
     978              : !$OMP             PRIVATE(k,j,i,my_rho,my_rho_n,my_rho_n2) &
     979            0 : !$OMP             COLLAPSE(3)
     980              :                DO k = bo(1, 3), bo(2, 3)
     981              :                   DO j = bo(1, 2), bo(2, 2)
     982              :                      DO i = bo(1, 1), bo(2, 1)
     983              :                         my_rho = rhoa(i, j, k) + rhob(i, j, k)
     984              :                         IF (my_rho < rho_smooth_cutoff) THEN
     985              :                            IF (my_rho < rho_cutoff) THEN
     986              :                               pot(i, j, k) = 0.0_dp
     987              :                            ELSEIF (my_rho < rho_smooth_cutoff_2) THEN
     988              :                               my_rho_n = (my_rho - rho_cutoff)/rho_smooth_cutoff_range_2
     989              :                               my_rho_n2 = my_rho_n*my_rho_n
     990              :                               pot(i, j, k) = pot(i, j, k)* &
     991              :                                              my_rho_n2*(my_rho_n - 0.5_dp*my_rho_n2) + &
     992              :                                              my_e_0_scale_factor*e_0(i, j, k)* &
     993              :                                              my_rho_n2*(3.0_dp - 2.0_dp*my_rho_n) &
     994              :                                              /rho_smooth_cutoff_range_2
     995              :                            ELSE
     996              :                               my_rho_n = 2.0_dp - (my_rho - rho_cutoff)/rho_smooth_cutoff_range_2
     997              :                               my_rho_n2 = my_rho_n*my_rho_n
     998              :                               pot(i, j, k) = pot(i, j, k)* &
     999              :                                              (1.0_dp - my_rho_n2*(my_rho_n - 0.5_dp*my_rho_n2)) &
    1000              :                                              + my_e_0_scale_factor*e_0(i, j, k)* &
    1001              :                                              my_rho_n2*(3.0_dp - 2.0_dp*my_rho_n) &
    1002              :                                              /rho_smooth_cutoff_range_2
    1003              :                            END IF
    1004              :                         END IF
    1005              :                      END DO
    1006              :                   END DO
    1007              :                END DO
    1008              : !$OMP END PARALLEL DO
    1009              :             END IF
    1010              :          ELSE
    1011            2 :             IF (ASSOCIATED(rho)) THEN
    1012              : !$OMP PARALLEL DO DEFAULT(NONE) &
    1013              : !$OMP             SHARED(bo,pot,rho_cutoff,rho_smooth_cutoff,rho_smooth_cutoff_2, &
    1014              : !$OMP                    rho_smooth_cutoff_range_2,rho) &
    1015              : !$OMP             PRIVATE(k,j,i,my_rho,my_rho_n,my_rho_n2) &
    1016            2 : !$OMP             COLLAPSE(3)
    1017              :                DO k = bo(1, 3), bo(2, 3)
    1018              :                   DO j = bo(1, 2), bo(2, 2)
    1019              :                      DO i = bo(1, 1), bo(2, 1)
    1020              :                         my_rho = rho(i, j, k)
    1021              :                         IF (my_rho < rho_smooth_cutoff) THEN
    1022              :                            IF (my_rho < rho_cutoff) THEN
    1023              :                               pot(i, j, k) = 0.0_dp
    1024              :                            ELSEIF (my_rho < rho_smooth_cutoff_2) THEN
    1025              :                               my_rho_n = (my_rho - rho_cutoff)/rho_smooth_cutoff_range_2
    1026              :                               my_rho_n2 = my_rho_n*my_rho_n
    1027              :                               pot(i, j, k) = pot(i, j, k)* &
    1028              :                                              my_rho_n2*(my_rho_n - 0.5_dp*my_rho_n2)
    1029              :                            ELSE
    1030              :                               my_rho_n = 2.0_dp - (my_rho - rho_cutoff)/rho_smooth_cutoff_range_2
    1031              :                               my_rho_n2 = my_rho_n*my_rho_n
    1032              :                               pot(i, j, k) = pot(i, j, k)* &
    1033              :                                              (1.0_dp - my_rho_n2*(my_rho_n - 0.5_dp*my_rho_n2))
    1034              :                            END IF
    1035              :                         END IF
    1036              :                      END DO
    1037              :                   END DO
    1038              :                END DO
    1039              : !$OMP END PARALLEL DO
    1040              :             ELSE
    1041              : !$OMP PARALLEL DO DEFAULT(NONE) &
    1042              : !$OMP             SHARED(bo,pot,rho_cutoff,rho_smooth_cutoff,rho_smooth_cutoff_2, &
    1043              : !$OMP                    rho_smooth_cutoff_range_2,rhoa,rhob) &
    1044              : !$OMP             PRIVATE(k,j,i,my_rho,my_rho_n,my_rho_n2) &
    1045            0 : !$OMP             COLLAPSE(3)
    1046              :                DO k = bo(1, 3), bo(2, 3)
    1047              :                   DO j = bo(1, 2), bo(2, 2)
    1048              :                      DO i = bo(1, 1), bo(2, 1)
    1049              :                         my_rho = rhoa(i, j, k) + rhob(i, j, k)
    1050              :                         IF (my_rho < rho_smooth_cutoff) THEN
    1051              :                            IF (my_rho < rho_cutoff) THEN
    1052              :                               pot(i, j, k) = 0.0_dp
    1053              :                            ELSEIF (my_rho < rho_smooth_cutoff_2) THEN
    1054              :                               my_rho_n = (my_rho - rho_cutoff)/rho_smooth_cutoff_range_2
    1055              :                               my_rho_n2 = my_rho_n*my_rho_n
    1056              :                               pot(i, j, k) = pot(i, j, k)* &
    1057              :                                              my_rho_n2*(my_rho_n - 0.5_dp*my_rho_n2)
    1058              :                            ELSE
    1059              :                               my_rho_n = 2.0_dp - (my_rho - rho_cutoff)/rho_smooth_cutoff_range_2
    1060              :                               my_rho_n2 = my_rho_n*my_rho_n
    1061              :                               pot(i, j, k) = pot(i, j, k)* &
    1062              :                                              (1.0_dp - my_rho_n2*(my_rho_n - 0.5_dp*my_rho_n2))
    1063              :                            END IF
    1064              :                         END IF
    1065              :                      END DO
    1066              :                   END DO
    1067              :                END DO
    1068              : !$OMP END PARALLEL DO
    1069              :             END IF
    1070              :          END IF
    1071              :       END IF
    1072       259537 :    END SUBROUTINE smooth_cutoff
    1073              : 
    1074           64 :    SUBROUTINE calc_xc_density(pot, rho, rho_cutoff)
    1075              :       TYPE(pw_r3d_rs_type), INTENT(INOUT)                       :: pot
    1076              :       TYPE(pw_r3d_rs_type), DIMENSION(:), INTENT(INOUT)         :: rho
    1077              :       REAL(kind=dp), INTENT(in)                          :: rho_cutoff
    1078              : 
    1079              :       INTEGER                                            :: i, j, k, nspins
    1080              :       INTEGER, DIMENSION(2, 3)                           :: bo
    1081              :       REAL(kind=dp)                                      :: eps1, eps2, my_rho, my_pot
    1082              : 
    1083          256 :       bo(1, :) = LBOUND(pot%array)
    1084          256 :       bo(2, :) = UBOUND(pot%array)
    1085           64 :       nspins = SIZE(rho)
    1086              : 
    1087           64 :       eps1 = rho_cutoff*1.E-4_dp
    1088           64 :       eps2 = rho_cutoff
    1089              : 
    1090         3160 :       DO k = bo(1, 3), bo(2, 3)
    1091       161272 :          DO j = bo(1, 2), bo(2, 2)
    1092      4529376 :             DO i = bo(1, 1), bo(2, 1)
    1093      4368168 :                my_pot = pot%array(i, j, k)
    1094      4368168 :                IF (nspins == 2) THEN
    1095       339714 :                   my_rho = rho(1)%array(i, j, k) + rho(2)%array(i, j, k)
    1096              :                ELSE
    1097      4028454 :                   my_rho = rho(1)%array(i, j, k)
    1098              :                END IF
    1099      4526280 :                IF (my_rho > eps1) THEN
    1100      4139578 :                   pot%array(i, j, k) = my_pot/my_rho
    1101       228590 :                ELSE IF (my_rho < eps2) THEN
    1102       228590 :                   pot%array(i, j, k) = 0.0_dp
    1103              :                ELSE
    1104            0 :                   pot%array(i, j, k) = MIN(my_pot/my_rho, my_rho**(1._dp/3._dp))
    1105              :                END IF
    1106              :             END DO
    1107              :          END DO
    1108              :       END DO
    1109              : 
    1110           64 :    END SUBROUTINE calc_xc_density
    1111              : 
    1112              : ! **************************************************************************************************
    1113              : !> \brief Exchange and Correlation functional calculations
    1114              : !> \param vxc_rho will contain the v_xc part that depend on rho
    1115              : !>        (if one of the chosen xc functionals has it it is allocated and you
    1116              : !>        are responsible for it)
    1117              : !> \param vxc_tau will contain the kinetic tau part of v_xc
    1118              : !>        (if one of the chosen xc functionals has it it is allocated and you
    1119              : !>        are responsible for it)
    1120              : !> \param exc the xc energy
    1121              : !> \param rho_r the value of the density in the real space
    1122              : !> \param rho_g value of the density in the g space (needs to be associated
    1123              : !>        only for gradient corrections)
    1124              : !> \param tau value of the kinetic density tau on the grid (can be null,
    1125              : !>        used only with meta functionals)
    1126              : !> \param xc_section which functional to calculate, and how to do it
    1127              : !> \param pw_pool the pool for the grids
    1128              : !> \param compute_virial ...
    1129              : !> \param virial_xc ...
    1130              : !> \param exc_r the value of the xc functional in the real space
    1131              : !> \par History
    1132              : !>      JGH (13-Jun-2002): adaptation to new functionals
    1133              : !>      Fawzi (11.2002): drho_g(1:3)->drho_g
    1134              : !>      Fawzi (1.2003). lsd version
    1135              : !>      Fawzi (11.2003): version using the new xc interface
    1136              : !>      Fawzi (03.2004): fft free for smoothed density and derivs, gga lsd
    1137              : !>      Fawzi (04.2004): metafunctionals
    1138              : !>      mguidon (12.2008) : laplace functionals
    1139              : !> \author fawzi; based LDA version of JGH, based on earlier version of apsi
    1140              : !> \note
    1141              : !>      Beware: some really dirty pointer handling!
    1142              : !>      energy should be kept consistent with xc_exc_calc
    1143              : ! **************************************************************************************************
    1144       113247 :    SUBROUTINE xc_vxc_pw_create(vxc_rho, vxc_tau, exc, rho_r, rho_g, tau, xc_section, &
    1145              :                                pw_pool, compute_virial, virial_xc, exc_r)
    1146              :       TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER             :: vxc_rho, vxc_tau
    1147              :       REAL(KIND=dp), INTENT(out)                         :: exc
    1148              :       TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER               :: rho_r, tau
    1149              :       TYPE(pw_c1d_gs_type), DIMENSION(:), POINTER :: rho_g
    1150              :       TYPE(section_vals_type), POINTER                   :: xc_section
    1151              :       TYPE(pw_pool_type), POINTER                        :: pw_pool
    1152              :       LOGICAL                                            :: compute_virial
    1153              :       REAL(KIND=dp), DIMENSION(3, 3), INTENT(OUT)        :: virial_xc
    1154              :       TYPE(pw_r3d_rs_type), INTENT(INOUT), OPTIONAL            :: exc_r
    1155              : 
    1156              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'xc_vxc_pw_create'
    1157              :       INTEGER, DIMENSION(2), PARAMETER :: norm_drho_spin_name = [deriv_norm_drhoa, deriv_norm_drhob]
    1158              : 
    1159              :       INTEGER                                            :: handle, idir, ispin, jdir, &
    1160              :                                                             npoints, nspins, &
    1161              :                                                             xc_deriv_method_id, xc_rho_smooth_id, deriv_id
    1162              :       INTEGER, DIMENSION(2, 3)                           :: bo
    1163              :       LOGICAL                                            :: dealloc_pw_to_deriv, has_laplace, &
    1164              :                                                             has_tau, lsd, use_virial, has_gradient, &
    1165              :                                                             has_derivs, has_rho, dealloc_pw_to_deriv_rho
    1166              :       REAL(KIND=dp)                                      :: density_smooth_cut_range, drho_cutoff, &
    1167              :                                                             rho_cutoff
    1168       113247 :       REAL(kind=dp), DIMENSION(:, :, :), POINTER         :: deriv_data, norm_drho, norm_drho_spin, &
    1169       226494 :                                                             rho, rhoa, rhob
    1170              :       TYPE(cp_sll_xc_deriv_type), POINTER                :: pos
    1171              :       TYPE(pw_grid_type), POINTER                        :: pw_grid
    1172       792729 :       TYPE(pw_r3d_rs_type), DIMENSION(3)                      :: pw_to_deriv, pw_to_deriv_rho
    1173              :       TYPE(pw_c1d_gs_type) :: tmp_g, vxc_g
    1174              :       TYPE(pw_r3d_rs_type)                                      ::  v_drho_r, virial_pw
    1175              :       TYPE(xc_derivative_set_type)                       :: deriv_set
    1176              :       TYPE(xc_derivative_type), POINTER                  :: deriv_att
    1177              :       TYPE(xc_rho_set_type)                              :: rho_set
    1178              : 
    1179       113247 :       CALL timeset(routineN, handle)
    1180       113247 :       NULLIFY (norm_drho_spin, norm_drho, pos)
    1181              : 
    1182       113247 :       pw_grid => rho_r(1)%pw_grid
    1183              : 
    1184       113247 :       CPASSERT(ASSOCIATED(xc_section))
    1185       113247 :       CPASSERT(ASSOCIATED(pw_pool))
    1186       113247 :       CPASSERT(.NOT. ASSOCIATED(vxc_rho))
    1187       113247 :       CPASSERT(.NOT. ASSOCIATED(vxc_tau))
    1188       113247 :       nspins = SIZE(rho_r)
    1189       113247 :       lsd = (nspins /= 1)
    1190       113247 :       IF (lsd) THEN
    1191        22791 :          CPASSERT(nspins == 2)
    1192              :       END IF
    1193              : 
    1194       113247 :       use_virial = compute_virial
    1195       113247 :       virial_xc = 0.0_dp
    1196              : 
    1197      1132470 :       bo = rho_r(1)%pw_grid%bounds_local
    1198       113247 :       npoints = (bo(2, 1) - bo(1, 1) + 1)*(bo(2, 2) - bo(1, 2) + 1)*(bo(2, 3) - bo(1, 3) + 1)
    1199              : 
    1200              :       ! calculate the potential derivatives
    1201              :       CALL xc_rho_set_and_dset_create(rho_set=rho_set, deriv_set=deriv_set, &
    1202              :                                       deriv_order=1, rho_r=rho_r, rho_g=rho_g, tau=tau, &
    1203              :                                       xc_section=xc_section, &
    1204              :                                       pw_pool=pw_pool, &
    1205       113247 :                                       calc_potential=.TRUE.)
    1206              : 
    1207              :       CALL section_vals_val_get(xc_section, "XC_GRID%XC_DERIV", &
    1208       113247 :                                 i_val=xc_deriv_method_id)
    1209              :       CALL section_vals_val_get(xc_section, "XC_GRID%XC_SMOOTH_RHO", &
    1210       113247 :                                 i_val=xc_rho_smooth_id)
    1211              :       CALL section_vals_val_get(xc_section, "DENSITY_SMOOTH_CUTOFF_RANGE", &
    1212       113247 :                                 r_val=density_smooth_cut_range)
    1213              : 
    1214              :       CALL xc_rho_set_get(rho_set, rho_cutoff=rho_cutoff, &
    1215       113247 :                           drho_cutoff=drho_cutoff)
    1216              : 
    1217       113247 :       CALL check_for_derivatives(deriv_set, lsd, has_rho, has_gradient, has_tau, has_laplace)
    1218              :       ! check for unknown derivatives
    1219       113247 :       has_derivs = has_rho .OR. has_gradient .OR. has_tau .OR. has_laplace
    1220              : 
    1221       475779 :       ALLOCATE (vxc_rho(nspins))
    1222              : 
    1223              :       CALL xc_rho_set_get(rho_set, rho=rho, rhoa=rhoa, rhob=rhob, &
    1224       113247 :                           can_return_null=.TRUE.)
    1225              : 
    1226              :       ! recover the vxc arrays
    1227       113247 :       IF (lsd) THEN
    1228        22791 :          CALL xc_dset_recover_pw(deriv_set, [deriv_rhoa], vxc_rho(1), pw_grid, pw_pool)
    1229        22791 :          CALL xc_dset_recover_pw(deriv_set, [deriv_rhob], vxc_rho(2), pw_grid, pw_pool)
    1230              : 
    1231              :       ELSE
    1232        90456 :          CALL xc_dset_recover_pw(deriv_set, [deriv_rho], vxc_rho(1), pw_grid, pw_pool)
    1233              :       END IF
    1234              : 
    1235       113247 :       deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drho])
    1236       113247 :       IF (ASSOCIATED(deriv_att)) THEN
    1237        61363 :          CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
    1238              : 
    1239              :          CALL xc_rho_set_get(rho_set, norm_drho=norm_drho, &
    1240              :                              rho_cutoff=rho_cutoff, &
    1241              :                              drho_cutoff=drho_cutoff, &
    1242        61363 :                              can_return_null=.TRUE.)
    1243        61363 :          CALL xc_rho_set_recover_pw(rho_set, pw_grid, pw_pool, dealloc_pw_to_deriv_rho, drho=pw_to_deriv_rho)
    1244              : 
    1245        61363 :          CPASSERT(ASSOCIATED(deriv_data))
    1246        61363 :          IF (use_virial) THEN
    1247         1568 :             CALL pw_pool%create_pw(virial_pw)
    1248         1568 :             CALL pw_zero(virial_pw)
    1249         6272 :             DO idir = 1, 3
    1250         4704 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(virial_pw,pw_to_deriv_rho,deriv_data,idir)
    1251              :                virial_pw%array(:, :, :) = pw_to_deriv_rho(idir)%array(:, :, :)*deriv_data(:, :, :)
    1252              : !$OMP END PARALLEL WORKSHARE
    1253        15680 :                DO jdir = 1, idir
    1254              :                   virial_xc(idir, jdir) = -pw_grid%dvol* &
    1255              :                                           accurate_dot_product(virial_pw%array(:, :, :), &
    1256         9408 :                                                                pw_to_deriv_rho(jdir)%array(:, :, :))
    1257        14112 :                   virial_xc(jdir, idir) = virial_xc(idir, jdir)
    1258              :                END DO
    1259              :             END DO
    1260         1568 :             CALL pw_pool%give_back_pw(virial_pw)
    1261              :          END IF ! use_virial
    1262       245452 :          DO idir = 1, 3
    1263       184089 :             CPASSERT(ASSOCIATED(pw_to_deriv_rho(idir)%array))
    1264       245452 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(deriv_data,pw_to_deriv_rho,idir)
    1265              :             pw_to_deriv_rho(idir)%array(:, :, :) = pw_to_deriv_rho(idir)%array(:, :, :)*deriv_data(:, :, :)
    1266              : !$OMP END PARALLEL WORKSHARE
    1267              :          END DO
    1268              : 
    1269              :          ! Deallocate pw to save memory
    1270        61363 :          CALL pw_pool%give_back_cr3d(deriv_att%deriv_data)
    1271              : 
    1272              :       END IF
    1273              : 
    1274       113247 :       IF ((has_gradient .AND. xc_requires_tmp_g(xc_deriv_method_id)) .OR. pw_grid%spherical) THEN
    1275        61133 :          CALL pw_pool%create_pw(vxc_g)
    1276        61133 :          IF (.NOT. pw_grid%spherical) THEN
    1277        61133 :             CALL pw_pool%create_pw(tmp_g)
    1278              :          END IF
    1279              :       END IF
    1280              : 
    1281       249285 :       DO ispin = 1, nspins
    1282              : 
    1283       136038 :          IF (lsd) THEN
    1284        45582 :             IF (ispin == 1) THEN
    1285              :                CALL xc_rho_set_get(rho_set, norm_drhoa=norm_drho_spin, &
    1286        22791 :                                    can_return_null=.TRUE.)
    1287        22791 :                IF (ASSOCIATED(norm_drho_spin)) CALL xc_rho_set_recover_pw( &
    1288        14598 :                   rho_set, pw_grid, pw_pool, dealloc_pw_to_deriv, drhoa=pw_to_deriv)
    1289              :             ELSE
    1290              :                CALL xc_rho_set_get(rho_set, norm_drhob=norm_drho_spin, &
    1291        22791 :                                    can_return_null=.TRUE.)
    1292        22791 :                IF (ASSOCIATED(norm_drho_spin)) CALL xc_rho_set_recover_pw( &
    1293        14598 :                   rho_set, pw_grid, pw_pool, dealloc_pw_to_deriv, drhob=pw_to_deriv)
    1294              :             END IF
    1295              : 
    1296        91164 :             deriv_att => xc_dset_get_derivative(deriv_set, [norm_drho_spin_name(ispin)])
    1297        45582 :             IF (ASSOCIATED(deriv_att)) THEN
    1298              :                CPASSERT(lsd)
    1299        29196 :                CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
    1300              : 
    1301        29196 :                IF (use_virial) THEN
    1302          104 :                   CALL pw_pool%create_pw(virial_pw)
    1303          104 :                   CALL pw_zero(virial_pw)
    1304          416 :                   DO idir = 1, 3
    1305          312 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(deriv_data,pw_to_deriv,virial_pw,idir)
    1306              :                      virial_pw%array(:, :, :) = pw_to_deriv(idir)%array(:, :, :)*deriv_data(:, :, :)
    1307              : !$OMP END PARALLEL WORKSHARE
    1308         1040 :                      DO jdir = 1, idir
    1309              :                         virial_xc(idir, jdir) = virial_xc(idir, jdir) - pw_grid%dvol* &
    1310              :                                                 accurate_dot_product(virial_pw%array(:, :, :), &
    1311          624 :                                                                      pw_to_deriv(jdir)%array(:, :, :))
    1312          936 :                         virial_xc(jdir, idir) = virial_xc(idir, jdir)
    1313              :                      END DO
    1314              :                   END DO
    1315          104 :                   CALL pw_pool%give_back_pw(virial_pw)
    1316              :                END IF ! use_virial
    1317              : 
    1318       116784 :                DO idir = 1, 3
    1319       116784 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(deriv_data,idir,pw_to_deriv)
    1320              :                   pw_to_deriv(idir)%array(:, :, :) = deriv_data(:, :, :)*pw_to_deriv(idir)%array(:, :, :)
    1321              : !$OMP END PARALLEL WORKSHARE
    1322              :                END DO
    1323              :             END IF ! deriv_att
    1324              : 
    1325              :          END IF ! LSD
    1326              : 
    1327       136038 :          IF (ASSOCIATED(pw_to_deriv_rho(1)%array)) THEN
    1328        75203 :             IF (.NOT. ASSOCIATED(pw_to_deriv(1)%array)) THEN
    1329        47523 :                pw_to_deriv = pw_to_deriv_rho
    1330        47523 :                dealloc_pw_to_deriv = ((.NOT. lsd) .OR. (ispin == 2))
    1331        47523 :                dealloc_pw_to_deriv = dealloc_pw_to_deriv .AND. dealloc_pw_to_deriv_rho
    1332              :             ELSE
    1333              :                ! This branch is called in case of open-shell systems
    1334              :                ! Add the contributions from norm_drho and norm_drho_spin
    1335       110720 :                DO idir = 1, 3
    1336        83040 :                   CALL pw_axpy(pw_to_deriv_rho(idir), pw_to_deriv(idir))
    1337       110720 :                   IF (ispin == 2) THEN
    1338        41520 :                      IF (dealloc_pw_to_deriv_rho) THEN
    1339        41520 :                         CALL pw_pool%give_back_pw(pw_to_deriv_rho(idir))
    1340              :                      END IF
    1341              :                   END IF
    1342              :                END DO
    1343              :             END IF
    1344              :          END IF
    1345              : 
    1346       136038 :          IF (ASSOCIATED(pw_to_deriv(1)%array)) THEN
    1347       306876 :             DO idir = 1, 3
    1348       306876 :                CALL pw_scale(pw_to_deriv(idir), -1.0_dp)
    1349              :             END DO
    1350              : 
    1351        76719 :             CALL xc_pw_divergence(xc_deriv_method_id, pw_to_deriv, tmp_g, vxc_g, vxc_rho(ispin))
    1352              : 
    1353        76719 :             IF (dealloc_pw_to_deriv) THEN
    1354       306876 :             DO idir = 1, 3
    1355       306876 :                CALL pw_pool%give_back_pw(pw_to_deriv(idir))
    1356              :             END DO
    1357              :             END IF
    1358              :          END IF
    1359              : 
    1360              :          ! Add laplace part to vxc_rho
    1361       136038 :          IF (has_laplace) THEN
    1362         1092 :             IF (lsd) THEN
    1363          472 :                IF (ispin == 1) THEN
    1364              :                   deriv_id = deriv_laplace_rhoa
    1365              :                ELSE
    1366          236 :                   deriv_id = deriv_laplace_rhob
    1367              :                END IF
    1368              :             ELSE
    1369              :                deriv_id = deriv_laplace_rho
    1370              :             END IF
    1371              : 
    1372         2184 :             CALL xc_dset_recover_pw(deriv_set, [deriv_id], pw_to_deriv(1), pw_grid)
    1373              : 
    1374         1092 :             IF (use_virial) CALL virial_laplace(rho_r(ispin), pw_pool, virial_xc, pw_to_deriv(1)%array)
    1375              : 
    1376         1092 :             CALL xc_pw_laplace(pw_to_deriv(1), pw_pool, xc_deriv_method_id)
    1377              : 
    1378         1092 :             CALL pw_axpy(pw_to_deriv(1), vxc_rho(ispin))
    1379              : 
    1380         1092 :             CALL pw_pool%give_back_pw(pw_to_deriv(1))
    1381              :          END IF
    1382              : 
    1383       136038 :          IF (pw_grid%spherical) THEN
    1384              :             ! filter vxc
    1385            0 :             CALL pw_transfer(vxc_rho(ispin), vxc_g)
    1386            0 :             CALL pw_transfer(vxc_g, vxc_rho(ispin))
    1387              :          END IF
    1388              :          CALL smooth_cutoff(pot=vxc_rho(ispin)%array, rho=rho, rhoa=rhoa, rhob=rhob, &
    1389              :                             rho_cutoff=rho_cutoff*density_smooth_cut_range, &
    1390       136038 :                             rho_smooth_cutoff_range=density_smooth_cut_range)
    1391              : 
    1392       136038 :          v_drho_r = vxc_rho(ispin)
    1393       136038 :          CALL pw_pool%create_pw(vxc_rho(ispin))
    1394       136038 :          CALL xc_pw_smooth(v_drho_r, vxc_rho(ispin), xc_rho_smooth_id)
    1395       249285 :          CALL pw_pool%give_back_pw(v_drho_r)
    1396              :       END DO
    1397              : 
    1398       113247 :       CALL pw_pool%give_back_pw(vxc_g)
    1399       113247 :       CALL pw_pool%give_back_pw(tmp_g)
    1400              : 
    1401              :       ! 0-deriv -> value of exc
    1402              :       ! this has to be kept consistent with xc_exc_calc
    1403       113247 :       IF (has_derivs) THEN
    1404       112929 :          CALL xc_dset_recover_pw(deriv_set, [INTEGER::], v_drho_r, pw_grid)
    1405              : 
    1406              :          CALL smooth_cutoff(pot=v_drho_r%array, rho=rho, rhoa=rhoa, rhob=rhob, &
    1407              :                             rho_cutoff=rho_cutoff, &
    1408       112929 :                             rho_smooth_cutoff_range=density_smooth_cut_range)
    1409              : 
    1410       112929 :          exc = pw_integrate_function(v_drho_r)
    1411              :          !
    1412              :          ! return the xc functional value at the grid points
    1413              :          !
    1414       112929 :          IF (PRESENT(exc_r)) THEN
    1415           96 :             exc_r = v_drho_r
    1416              :          ELSE
    1417       112833 :             CALL v_drho_r%release()
    1418              :          END IF
    1419              :       ELSE
    1420          318 :          exc = 0.0_dp
    1421              :       END IF
    1422              : 
    1423       113247 :       CALL xc_rho_set_release(rho_set, pw_pool=pw_pool)
    1424              : 
    1425              :       ! tau part
    1426       113247 :       IF (has_tau) THEN
    1427         8374 :          ALLOCATE (vxc_tau(nspins))
    1428         2580 :          IF (lsd) THEN
    1429          634 :             CALL xc_dset_recover_pw(deriv_set, [deriv_tau_a], vxc_tau(1), pw_grid)
    1430          634 :             CALL xc_dset_recover_pw(deriv_set, [deriv_tau_b], vxc_tau(2), pw_grid)
    1431              :          ELSE
    1432         1946 :             CALL xc_dset_recover_pw(deriv_set, [deriv_tau], vxc_tau(1), pw_grid)
    1433              :          END IF
    1434         5794 :          DO ispin = 1, nspins
    1435         5794 :             CPASSERT(ASSOCIATED(vxc_tau(ispin)%array))
    1436              :          END DO
    1437              :       END IF
    1438       113247 :       CALL xc_dset_release(deriv_set)
    1439              : 
    1440       113247 :       CALL timestop(handle)
    1441              : 
    1442      2378187 :    END SUBROUTINE xc_vxc_pw_create
    1443              : 
    1444              : ! **************************************************************************************************
    1445              : !> \brief calculates just the exchange and correlation energy
    1446              : !>      (no vxc)
    1447              : !> \param rho_r      realspace density on the grid
    1448              : !> \param rho_g      g-space density on the grid
    1449              : !> \param tau        kinetic energy density on the grid
    1450              : !> \param xc_section XC parameters
    1451              : !> \param pw_pool    pool of plain-wave grids
    1452              : !> \return the XC energy
    1453              : !> \par History
    1454              : !>      11.2003 created [fawzi]
    1455              : !> \author fawzi
    1456              : !> \note
    1457              : !>      has to be kept consistent with xc_vxc_pw_create
    1458              : ! **************************************************************************************************
    1459        21136 :    FUNCTION xc_exc_calc(rho_r, rho_g, tau, xc_section, pw_pool) &
    1460              :       RESULT(exc)
    1461              :       TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER               :: rho_r, tau
    1462              :       TYPE(pw_c1d_gs_type), DIMENSION(:), POINTER :: rho_g
    1463              :       TYPE(section_vals_type), POINTER                   :: xc_section
    1464              :       TYPE(pw_pool_type), POINTER                        :: pw_pool
    1465              :       REAL(kind=dp)                                      :: exc
    1466              : 
    1467              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'xc_exc_calc'
    1468              : 
    1469              :       INTEGER                                            :: handle
    1470              :       REAL(dp)                                           :: density_smooth_cut_range, rho_cutoff
    1471        10568 :       REAL(dp), DIMENSION(:, :, :), POINTER              :: e_0
    1472              :       TYPE(xc_derivative_set_type)                       :: deriv_set
    1473              :       TYPE(xc_derivative_type), POINTER                  :: deriv
    1474              :       TYPE(xc_rho_set_type)                              :: rho_set
    1475              : 
    1476        10568 :       CALL timeset(routineN, handle)
    1477        10568 :       NULLIFY (deriv, e_0)
    1478        10568 :       exc = 0.0_dp
    1479              : 
    1480              :       ! this has to be consistent with what is done in xc_vxc_pw_create
    1481              :       CALL xc_rho_set_and_dset_create(rho_set=rho_set, &
    1482              :                                       deriv_set=deriv_set, deriv_order=0, &
    1483              :                                       rho_r=rho_r, rho_g=rho_g, tau=tau, xc_section=xc_section, &
    1484              :                                       pw_pool=pw_pool, &
    1485        10568 :                                       calc_potential=.FALSE.)
    1486        10568 :       deriv => xc_dset_get_derivative(deriv_set, [INTEGER::])
    1487              : 
    1488        10568 :       IF (ASSOCIATED(deriv)) THEN
    1489        10568 :          CALL xc_derivative_get(deriv, deriv_data=e_0)
    1490              : 
    1491              :          CALL section_vals_val_get(xc_section, "DENSITY_CUTOFF", &
    1492        10568 :                                    r_val=rho_cutoff)
    1493              :          CALL section_vals_val_get(xc_section, "DENSITY_SMOOTH_CUTOFF_RANGE", &
    1494        10568 :                                    r_val=density_smooth_cut_range)
    1495              :          CALL smooth_cutoff(pot=e_0, rho=rho_set%rho, &
    1496              :                             rhoa=rho_set%rhoa, rhob=rho_set%rhob, &
    1497              :                             rho_cutoff=rho_cutoff, &
    1498        10568 :                             rho_smooth_cutoff_range=density_smooth_cut_range)
    1499              : 
    1500        10568 :          exc = accurate_sum(e_0)*rho_r(1)%pw_grid%dvol
    1501        10568 :          IF (rho_r(1)%pw_grid%para%mode == PW_MODE_DISTRIBUTED) THEN
    1502        10430 :             CALL rho_r(1)%pw_grid%para%group%sum(exc)
    1503              :          END IF
    1504              : 
    1505        10568 :          CALL xc_rho_set_release(rho_set, pw_pool=pw_pool)
    1506        10568 :          CALL xc_dset_release(deriv_set)
    1507              :       END IF
    1508        10568 :       CALL timestop(handle)
    1509       200792 :    END FUNCTION xc_exc_calc
    1510              : 
    1511              : ! **************************************************************************************************
    1512              : !> \brief Caller routine to calculate the second order potential in the direction of rho1_r
    1513              : !> \param v_xc XC potential, will be allocated, to be integrated with the KS density
    1514              : !> \param v_xc_tau ...
    1515              : !> \param deriv_set XC derivatives from xc_prep_2nd_deriv
    1516              : !> \param rho_set XC rho set from KS rho from xc_prep_2nd_deriv
    1517              : !> \param rho1_r first-order density in r space
    1518              : !> \param rho1_g first-order density in g space
    1519              : !> \param tau1_r ...
    1520              : !> \param pw_pool pw pool to create new grids
    1521              : !> \param xc_section XC section to calculate the derivatives from
    1522              : !> \param gapw whether to carry out GAPW (not possible with numerical derivatives)
    1523              : !> \param vxg GAPW potential
    1524              : !> \param do_excitations ...
    1525              : !> \param do_triplet ...
    1526              : !> \param compute_virial ...
    1527              : !> \param virial_xc virial terms will be collected here
    1528              : ! **************************************************************************************************
    1529        14420 :    SUBROUTINE xc_calc_2nd_deriv(v_xc, v_xc_tau, deriv_set, rho_set, rho1_r, rho1_g, tau1_r, &
    1530              :                                 pw_pool, xc_section, gapw, vxg, &
    1531              :                                 do_excitations, do_sf, do_triplet, &
    1532              :                                 compute_virial, virial_xc)
    1533              : 
    1534              :       TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER        :: v_xc, v_xc_tau
    1535              :       TYPE(xc_derivative_set_type)                       :: deriv_set
    1536              :       TYPE(xc_rho_set_type)                              :: rho_set
    1537              :       TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER        :: rho1_r, tau1_r
    1538              :       TYPE(pw_c1d_gs_type), DIMENSION(:), POINTER        :: rho1_g
    1539              :       TYPE(pw_pool_type), INTENT(IN), POINTER            :: pw_pool
    1540              :       TYPE(section_vals_type), INTENT(IN), POINTER       :: xc_section
    1541              :       LOGICAL, INTENT(IN)                                :: gapw
    1542              :       REAL(KIND=dp), DIMENSION(:, :, :, :), OPTIONAL, &
    1543              :          POINTER                                         :: vxg
    1544              :       LOGICAL, INTENT(IN), OPTIONAL                      :: do_excitations, do_sf, &
    1545              :                                                             do_triplet, compute_virial
    1546              :       REAL(KIND=dp), DIMENSION(3, 3), INTENT(INOUT), &
    1547              :          OPTIONAL                                        :: virial_xc
    1548              : 
    1549              :       CHARACTER(len=*), PARAMETER :: routineN = 'xc_calc_2nd_deriv'
    1550              : 
    1551              :       INTEGER                                            :: handle, ispin, nspins
    1552              :       INTEGER, DIMENSION(2, 3)                           :: bo
    1553              :       LOGICAL                                            :: lsd, my_compute_virial, &
    1554              :                                                             my_do_excitations, my_do_sf, &
    1555              :                                                             my_do_triplet
    1556              :       REAL(KIND=dp)                                      :: fac
    1557              :       TYPE(section_vals_type), POINTER                   :: xc_fun_section
    1558              :       TYPE(xc_rho_cflags_type)                           :: needs
    1559              :       TYPE(xc_rho_set_type)                              :: rho1_set
    1560              : 
    1561        14420 :       CALL timeset(routineN, handle)
    1562              : 
    1563        14420 :       my_compute_virial = .FALSE.
    1564        14420 :       IF (PRESENT(compute_virial)) my_compute_virial = compute_virial
    1565              : 
    1566        14420 :       my_do_sf = .FALSE.
    1567        14420 :       IF (PRESENT(do_sf)) my_do_sf = do_sf
    1568              : 
    1569        14420 :       my_do_excitations = .FALSE.
    1570        14420 :       IF (PRESENT(do_excitations)) my_do_excitations = do_excitations
    1571              : 
    1572        14420 :       my_do_triplet = .FALSE.
    1573        14420 :       IF (PRESENT(do_triplet)) my_do_triplet = do_triplet
    1574              : 
    1575        14420 :       nspins = SIZE(rho1_r)
    1576        14420 :       lsd = (nspins == 2)
    1577        14420 :       IF (nspins == 1 .AND. my_do_excitations .AND. my_do_triplet) THEN
    1578            0 :          nspins = 2
    1579            0 :          lsd = .TRUE.
    1580        14420 :       ELSE IF (my_do_sf) THEN
    1581          104 :          nspins = 1
    1582          104 :          lsd = .TRUE.
    1583              :       END IF
    1584              : 
    1585        14420 :       NULLIFY (v_xc, v_xc_tau)
    1586        59674 :       ALLOCATE (v_xc(nspins))
    1587        30834 :       DO ispin = 1, nspins
    1588        16414 :          CALL pw_pool%create_pw(v_xc(ispin))
    1589        30834 :          CALL pw_zero(v_xc(ispin))
    1590              :       END DO
    1591              : 
    1592        14420 :       xc_fun_section => section_vals_get_subs_vals(xc_section, "XC_FUNCTIONAL")
    1593        14420 :       needs = xc_functionals_get_needs(xc_fun_section, lsd, .TRUE.)
    1594              : 
    1595        14420 :       IF (needs%tau .OR. needs%tau_spin) THEN
    1596          536 :          IF (.NOT. ASSOCIATED(tau1_r)) &
    1597            0 :             CPABORT("Tau-dependent functionals requires allocated kinetic energy density grid")
    1598         1736 :          ALLOCATE (v_xc_tau(nspins))
    1599         1200 :          DO ispin = 1, nspins
    1600          664 :             CALL pw_pool%create_pw(v_xc_tau(ispin))
    1601        15084 :             CALL pw_zero(v_xc_tau(ispin))
    1602              :          END DO
    1603              :       END IF
    1604              : 
    1605        14420 :       IF (section_get_lval(xc_section, "2ND_DERIV_ANALYTICAL")) THEN
    1606              :          !------!
    1607              :          ! rho1 !
    1608              :          !------!
    1609       141200 :          bo = rho1_r(1)%pw_grid%bounds_local
    1610              :          ! create the place where to store the argument for the functionals
    1611              :          CALL xc_rho_set_create(rho1_set, bo, &
    1612              :                                 rho_cutoff=section_get_rval(xc_section, "DENSITY_CUTOFF"), &
    1613              :                                 drho_cutoff=section_get_rval(xc_section, "GRADIENT_CUTOFF"), &
    1614        14120 :                                 tau_cutoff=section_get_rval(xc_section, "TAU_CUTOFF"))
    1615              : 
    1616              :          ! calculate the arguments needed by the functionals
    1617              :          CALL xc_rho_set_update(rho1_set, rho1_r, rho1_g, tau1_r, needs, &
    1618              :                                 section_get_ival(xc_section, "XC_GRID%XC_DERIV"), &
    1619              :                                 section_get_ival(xc_section, "XC_GRID%XC_SMOOTH_RHO"), &
    1620        14120 :                                 pw_pool, spinflip=my_do_sf)
    1621              : 
    1622        14120 :          fac = 0._dp
    1623        14120 :          IF (nspins == 1 .AND. my_do_excitations) THEN
    1624         1124 :             IF (my_do_triplet) fac = -1.0_dp
    1625              :          END IF
    1626              : 
    1627              :          CALL xc_calc_2nd_deriv_analytical(v_xc, v_xc_tau, deriv_set, rho_set, &
    1628              :                                            rho1_set, pw_pool, xc_section, gapw, vxg=vxg, spinflip=my_do_sf, &
    1629        14120 :                                            tddfpt_fac=fac, compute_virial=compute_virial, virial_xc=virial_xc)
    1630              : 
    1631        14120 :          CALL xc_rho_set_release(rho1_set)
    1632              : 
    1633              :       ELSE
    1634          300 :          IF (gapw) CPABORT("Numerical 2nd derivatives not implemented with GAPW")
    1635              : 
    1636              :          CALL xc_calc_2nd_deriv_numerical(v_xc, v_xc_tau, rho_set, rho1_r, rho1_g, tau1_r, &
    1637              :                                           pw_pool, xc_section, &
    1638              :                                           my_do_excitations .AND. my_do_triplet, &
    1639          300 :                                           compute_virial, virial_xc, deriv_set)
    1640              :       END IF
    1641              : 
    1642        14420 :       CALL timestop(handle)
    1643              : 
    1644       317240 :    END SUBROUTINE xc_calc_2nd_deriv
    1645              : 
    1646              : ! **************************************************************************************************
    1647              : !> \brief calculates 2nd derivative numerically
    1648              : !> \param v_xc potential to be calculated (has to be allocated already)
    1649              : !> \param v_tau tau-part of the potential to be calculated (has to be allocated already)
    1650              : !> \param rho_set KS density from xc_prep_2nd_deriv
    1651              : !> \param rho1_r first-order density in r-space
    1652              : !> \param rho1_g first-order density in g-space
    1653              : !> \param tau1_r first-order kinetic-energy density in r-space
    1654              : !> \param pw_pool pw pool for new grids
    1655              : !> \param xc_section XC section to calculate the derivatives from
    1656              : !> \param do_triplet ...
    1657              : !> \param calc_virial whether to calculate virial terms
    1658              : !> \param virial_xc collects stress tensor components (no metaGGAs!)
    1659              : !> \param deriv_set deriv set from xc_prep_2nd_deriv (only for virials)
    1660              : ! **************************************************************************************************
    1661          340 :    SUBROUTINE xc_calc_2nd_deriv_numerical(v_xc, v_tau, rho_set, rho1_r, rho1_g, tau1_r, &
    1662              :                                           pw_pool, xc_section, &
    1663              :                                           do_triplet, calc_virial, virial_xc, deriv_set)
    1664              : 
    1665              :       TYPE(pw_r3d_rs_type), DIMENSION(:), INTENT(IN), POINTER :: v_xc, v_tau
    1666              :       TYPE(xc_rho_set_type), INTENT(IN)                  :: rho_set
    1667              :       TYPE(pw_r3d_rs_type), DIMENSION(:), INTENT(IN), POINTER   :: rho1_r, tau1_r
    1668              :       TYPE(pw_c1d_gs_type), DIMENSION(:), INTENT(IN), POINTER :: rho1_g
    1669              :       TYPE(pw_pool_type), INTENT(IN), POINTER            :: pw_pool
    1670              :       TYPE(section_vals_type), INTENT(IN), POINTER       :: xc_section
    1671              :       LOGICAL, INTENT(IN)                                :: do_triplet
    1672              :       LOGICAL, INTENT(IN), OPTIONAL                      :: calc_virial
    1673              :       REAL(KIND=dp), DIMENSION(3, 3), INTENT(INOUT), &
    1674              :          OPTIONAL                                        :: virial_xc
    1675              :       TYPE(xc_derivative_set_type), OPTIONAL             :: deriv_set
    1676              : 
    1677              :       CHARACTER(len=*), PARAMETER :: routineN = 'xc_calc_2nd_deriv_numerical'
    1678              :       REAL(KIND=dp), DIMENSION(-4:4, 4), PARAMETER :: &
    1679              :          weights = RESHAPE([0.0_dp, 0.0_dp, 0.0_dp, -0.5_dp, 0.0_dp, 0.5_dp, 0.0_dp, 0.0_dp, 0.0_dp, &
    1680              :                            0.0_dp, 0.0_dp, 1.0_dp/12.0_dp, -2.0_dp/3.0_dp, 0.0_dp, 2.0_dp/3.0_dp, -1.0_dp/12.0_dp, 0.0_dp, 0.0_dp, &
    1681              :                             0.0_dp, -1.0_dp/60.0_dp, 0.15_dp, -0.75_dp, 0.0_dp, 0.75_dp, -0.15_dp, 1.0_dp/60.0_dp, 0.0_dp, &
    1682              :             1.0_dp/280.0_dp, -4.0_dp/105.0_dp, 0.2_dp, -0.8_dp, 0.0_dp, 0.8_dp, -0.2_dp, 4.0_dp/105.0_dp, -1.0_dp/280.0_dp], [9, 4])
    1683              : 
    1684              :       INTEGER                                            :: handle, idir, ispin, nspins, istep, nsteps
    1685              :       INTEGER, DIMENSION(2, 3)                           :: bo
    1686              :       LOGICAL                                            :: gradient_f, lsd, my_calc_virial, tau_f, laplace_f, rho_f
    1687              :       REAL(KIND=dp)                                      :: exc, gradient_cut, h, weight, step, rho_cutoff
    1688          340 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: dr1dr, dra1dra, drb1drb
    1689              :       REAL(KIND=dp), DIMENSION(3, 3)                     :: virial_dummy
    1690          340 :       REAL(KIND=dp), DIMENSION(:, :, :), POINTER         :: norm_drho, norm_drho2, norm_drho2a, &
    1691          340 :                                                             norm_drho2b, norm_drhoa, norm_drhob, &
    1692         1020 :                                                             rho, rho1, rho1a, rho1b, rhoa, rhob, &
    1693          680 :                                                             tau_a, tau_b, tau, tau1, tau1a, tau1b, laplace, laplace1, &
    1694          340 :                                                             laplacea, laplaceb, laplace1a, laplace1b, &
    1695          680 :                                                             laplace2, laplace2a, laplace2b, deriv_data
    1696         8160 :       TYPE(cp_3d_r_cp_type), DIMENSION(3)                :: drho, drho1, drho1a, drho1b, drhoa, drhob
    1697              :       TYPE(pw_r3d_rs_type)                                      :: v_drho, v_drhoa, v_drhob
    1698          340 :       TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER             :: vxc_rho, vxc_tau
    1699          340 :       TYPE(pw_c1d_gs_type), DIMENSION(:), POINTER :: rho_g
    1700          340 :       TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER               ::  rho_r, tau_r
    1701              :       TYPE(pw_r3d_rs_type)                                      :: virial_pw, v_laplace, v_laplacea, v_laplaceb
    1702              :       TYPE(section_vals_type), POINTER                   :: xc_fun_section
    1703              :       TYPE(xc_derivative_set_type)                       :: deriv_set1
    1704              :       TYPE(xc_rho_cflags_type)                           :: needs
    1705              :       TYPE(xc_rho_set_type)                              :: rho1_set, rho2_set
    1706              : 
    1707          340 :       CALL timeset(routineN, handle)
    1708              : 
    1709          340 :       my_calc_virial = .FALSE.
    1710          340 :       IF (PRESENT(calc_virial) .AND. PRESENT(virial_xc)) my_calc_virial = calc_virial
    1711              : 
    1712          340 :       nspins = SIZE(v_xc)
    1713              : 
    1714          340 :       NULLIFY (tau, tau_r, tau_a, tau_b)
    1715              : 
    1716          340 :       h = section_get_rval(xc_section, "STEP_SIZE")
    1717          340 :       nsteps = section_get_ival(xc_section, "NSTEPS")
    1718          340 :       IF (nsteps < LBOUND(weights, 2) .OR. nspins > UBOUND(weights, 2)) THEN
    1719            0 :          CPABORT("The number of steps must be a value from 1 to 4.")
    1720              :       END IF
    1721              : 
    1722          340 :       IF (nspins == 2) THEN
    1723          148 :          NULLIFY (vxc_rho, rho_g, vxc_tau)
    1724          444 :          ALLOCATE (rho_r(2))
    1725          444 :          DO ispin = 1, nspins
    1726          444 :             CALL pw_pool%create_pw(rho_r(ispin))
    1727              :          END DO
    1728          148 :          IF (ASSOCIATED(tau1_r) .AND. ASSOCIATED(v_tau)) THEN
    1729          162 :             ALLOCATE (tau_r(2))
    1730          162 :             DO ispin = 1, nspins
    1731          162 :                CALL pw_pool%create_pw(tau_r(ispin))
    1732              :             END DO
    1733              :          END IF
    1734          148 :          CALL xc_rho_set_get(rho_set, can_return_null=.TRUE., rhoa=rhoa, rhob=rhob, tau_a=tau_a, tau_b=tau_b)
    1735         1088 :          DO istep = -nsteps, nsteps
    1736          940 :             IF (istep == 0) CYCLE
    1737          792 :             weight = weights(istep, nsteps)/h
    1738          792 :             step = REAL(istep, dp)*h
    1739              :             CALL calc_resp_potential_numer_ab(rho_r, rho_g, rho1_r, rhoa, rhob, vxc_rho, &
    1740          792 :                                               tau_r, tau1_r, tau_a, tau_b, vxc_tau, xc_section, pw_pool, step)
    1741         2376 :             DO ispin = 1, nspins
    1742         1584 :                CALL pw_axpy(vxc_rho(ispin), v_xc(ispin), weight)
    1743         2376 :                IF (ASSOCIATED(vxc_tau) .AND. ASSOCIATED(v_tau)) THEN
    1744          456 :                   CALL pw_axpy(vxc_tau(ispin), v_tau(ispin), weight)
    1745              :                END IF
    1746              :             END DO
    1747         2376 :             DO ispin = 1, nspins
    1748         2376 :                CALL vxc_rho(ispin)%release()
    1749              :             END DO
    1750          792 :             DEALLOCATE (vxc_rho)
    1751          940 :             IF (ASSOCIATED(vxc_tau)) THEN
    1752          684 :                DO ispin = 1, nspins
    1753          684 :                   CALL vxc_tau(ispin)%release()
    1754              :                END DO
    1755          228 :                DEALLOCATE (vxc_tau)
    1756              :             END IF
    1757              :          END DO
    1758          192 :       ELSE IF (nspins == 1 .AND. do_triplet) THEN
    1759           20 :          NULLIFY (vxc_rho, vxc_tau, rho_g)
    1760           60 :          ALLOCATE (rho_r(2))
    1761           60 :          DO ispin = 1, 2
    1762           60 :             CALL pw_pool%create_pw(rho_r(ispin))
    1763              :          END DO
    1764           20 :          IF (ASSOCIATED(tau1_r) .AND. ASSOCIATED(v_tau)) THEN
    1765            0 :             ALLOCATE (tau_r(2))
    1766            0 :             DO ispin = 1, nspins
    1767            0 :                CALL pw_pool%create_pw(tau_r(ispin))
    1768              :             END DO
    1769              :          END IF
    1770           20 :          CALL xc_rho_set_get(rho_set, can_return_null=.TRUE., rhoa=rhoa, rhob=rhob, tau_a=tau_a, tau_b=tau_b)
    1771          160 :          DO istep = -nsteps, nsteps
    1772          140 :             IF (istep == 0) CYCLE
    1773          120 :             weight = weights(istep, nsteps)/h
    1774          120 :             step = REAL(istep, dp)*h
    1775              :             ! K(alpha,alpha)
    1776          120 : !$OMP PARALLEL DEFAULT(NONE) SHARED(rho_r,rhoa,rhob,step,rho1_r,tau_r,tau_a,tau_b,tau1_r)
    1777              : !$OMP WORKSHARE
    1778              :             rho_r(1)%array(:, :, :) = rhoa(:, :, :) + step*rho1_r(1)%array(:, :, :)
    1779              : !$OMP END WORKSHARE NOWAIT
    1780              : !$OMP WORKSHARE
    1781              :             rho_r(2)%array(:, :, :) = rhob(:, :, :)
    1782              : !$OMP END WORKSHARE NOWAIT
    1783              :             IF (ASSOCIATED(tau1_r)) THEN
    1784              : !$OMP WORKSHARE
    1785              :                tau_r(1)%array(:, :, :) = tau_a(:, :, :) + step*tau1_r(1)%array(:, :, :)
    1786              : !$OMP END WORKSHARE NOWAIT
    1787              : !$OMP WORKSHARE
    1788              :                tau_r(2)%array(:, :, :) = tau_b(:, :, :)
    1789              : !$OMP END WORKSHARE NOWAIT
    1790              :             END IF
    1791              : !$OMP END PARALLEL
    1792              :             CALL xc_vxc_pw_create(vxc_rho, vxc_tau, exc, rho_r, rho_g, tau_r, xc_section, &
    1793          120 :                                   pw_pool, .FALSE., virial_dummy)
    1794          120 :             CALL pw_axpy(vxc_rho(1), v_xc(1), weight)
    1795          120 :             IF (ASSOCIATED(vxc_tau) .AND. ASSOCIATED(v_tau)) THEN
    1796            0 :                CALL pw_axpy(vxc_tau(1), v_tau(1), weight)
    1797              :             END IF
    1798          360 :             DO ispin = 1, 2
    1799          360 :                CALL vxc_rho(ispin)%release()
    1800              :             END DO
    1801          120 :             DEALLOCATE (vxc_rho)
    1802          120 :             IF (ASSOCIATED(vxc_tau)) THEN
    1803            0 :             DO ispin = 1, 2
    1804            0 :                CALL vxc_tau(ispin)%release()
    1805              :             END DO
    1806            0 :             DEALLOCATE (vxc_tau)
    1807              :             END IF
    1808          120 : !$OMP PARALLEL DEFAULT(NONE) SHARED(rho_r,rhoa,rhob,step,rho1_r,tau_r,tau_a,tau_b,tau1_r)
    1809              : !$OMP WORKSHARE
    1810              :             ! K(alpha,beta)
    1811              :             rho_r(1)%array(:, :, :) = rhoa(:, :, :)
    1812              : !$OMP END WORKSHARE NOWAIT
    1813              : !$OMP WORKSHARE
    1814              :             rho_r(2)%array(:, :, :) = rhob(:, :, :) + step*rho1_r(1)%array(:, :, :)
    1815              : !$OMP END WORKSHARE NOWAIT
    1816              :             IF (ASSOCIATED(tau1_r)) THEN
    1817              : !$OMP WORKSHARE
    1818              :                tau_r(1)%array(:, :, :) = tau_a(:, :, :)
    1819              : !$OMP END WORKSHARE NOWAIT
    1820              : !$OMP WORKSHARE
    1821              :                tau_r(2)%array(:, :, :) = tau_b(:, :, :) + step*tau1_r(1)%array(:, :, :)
    1822              : !$OMP END WORKSHARE NOWAIT
    1823              :             END IF
    1824              : !$OMP END PARALLEL
    1825              :             CALL xc_vxc_pw_create(vxc_rho, vxc_tau, exc, rho_r, rho_g, tau_r, xc_section, &
    1826          120 :                                   pw_pool, .FALSE., virial_dummy)
    1827          120 :             CALL pw_axpy(vxc_rho(1), v_xc(1), weight)
    1828          120 :             IF (ASSOCIATED(vxc_tau) .AND. ASSOCIATED(v_tau)) THEN
    1829            0 :                CALL pw_axpy(vxc_tau(1), v_tau(1), weight)
    1830              :             END IF
    1831          360 :             DO ispin = 1, 2
    1832          360 :                CALL vxc_rho(ispin)%release()
    1833              :             END DO
    1834          120 :             DEALLOCATE (vxc_rho)
    1835          140 :             IF (ASSOCIATED(vxc_tau)) THEN
    1836            0 :             DO ispin = 1, 2
    1837            0 :                CALL vxc_tau(ispin)%release()
    1838              :             END DO
    1839            0 :             DEALLOCATE (vxc_tau)
    1840              :             END IF
    1841              :          END DO
    1842              :       ELSE
    1843          172 :          NULLIFY (vxc_rho, rho_r, rho_g, vxc_tau, tau_r, tau)
    1844          344 :          ALLOCATE (rho_r(1))
    1845          172 :          CALL pw_pool%create_pw(rho_r(1))
    1846          172 :          IF (ASSOCIATED(tau1_r) .AND. ASSOCIATED(v_tau)) THEN
    1847           92 :             ALLOCATE (tau_r(1))
    1848           46 :             CALL pw_pool%create_pw(tau_r(1))
    1849              :          END IF
    1850          172 :          CALL xc_rho_set_get(rho_set, can_return_null=.TRUE., rho=rho, tau=tau)
    1851         1280 :          DO istep = -nsteps, nsteps
    1852         1108 :             IF (istep == 0) CYCLE
    1853          936 :             weight = weights(istep, nsteps)/h
    1854          936 :             step = REAL(istep, dp)*h
    1855          936 : !$OMP PARALLEL DEFAULT(NONE) SHARED(rho_r,rho,step,rho1_r,tau1_r,tau,tau_r)
    1856              : !$OMP WORKSHARE
    1857              :             rho_r(1)%array(:, :, :) = rho(:, :, :) + step*rho1_r(1)%array(:, :, :)
    1858              : !$OMP END WORKSHARE NOWAIT
    1859              :             IF (ASSOCIATED(tau1_r) .AND. ASSOCIATED(tau) .AND. ASSOCIATED(tau1_r)) THEN
    1860              : !$OMP WORKSHARE
    1861              :                tau_r(1)%array(:, :, :) = tau(:, :, :) + step*tau1_r(1)%array(:, :, :)
    1862              : !$OMP END WORKSHARE NOWAIT
    1863              :             END IF
    1864              : !$OMP END PARALLEL
    1865              :             CALL xc_vxc_pw_create(vxc_rho, vxc_tau, exc, rho_r, rho_g, tau_r, xc_section, &
    1866          936 :                                   pw_pool, .FALSE., virial_dummy)
    1867          936 :             CALL pw_axpy(vxc_rho(1), v_xc(1), weight)
    1868          936 :             IF (ASSOCIATED(vxc_tau) .AND. ASSOCIATED(v_tau)) THEN
    1869          276 :                CALL pw_axpy(vxc_tau(1), v_tau(1), weight)
    1870              :             END IF
    1871          936 :             CALL vxc_rho(1)%release()
    1872          936 :             DEALLOCATE (vxc_rho)
    1873         1108 :             IF (ASSOCIATED(vxc_tau)) THEN
    1874          276 :                CALL vxc_tau(1)%release()
    1875          276 :                DEALLOCATE (vxc_tau)
    1876              :             END IF
    1877              :          END DO
    1878              :       END IF
    1879              : 
    1880          340 :       IF (my_calc_virial) THEN
    1881           36 :          lsd = (nspins == 2)
    1882           36 :          IF (nspins == 1 .AND. do_triplet) THEN
    1883            0 :             lsd = .TRUE.
    1884              :          END IF
    1885              : 
    1886           36 :          CALL check_for_derivatives(deriv_set, (nspins == 2), rho_f, gradient_f, tau_f, laplace_f)
    1887              : 
    1888              :          ! Calculate the virial terms
    1889              :          ! Those arising from the first derivatives are treated like in xc_calc_2nd_deriv_analytical
    1890              :          ! Those arising from the second derivatives are calculated numerically
    1891              :          ! We assume that all metaGGA functionals require the gradient
    1892           36 :          IF (gradient_f) THEN
    1893          360 :             bo = rho_set%local_bounds
    1894              : 
    1895              :             ! Create the work grid for the virial terms
    1896           36 :             CALL allocate_pw(virial_pw, pw_pool, bo)
    1897              : 
    1898           36 :             gradient_cut = section_get_rval(xc_section, "GRADIENT_CUTOFF")
    1899              : 
    1900              :             ! create the container to store the argument of the functionals
    1901              :             CALL xc_rho_set_create(rho1_set, bo, &
    1902              :                                    rho_cutoff=section_get_rval(xc_section, "DENSITY_CUTOFF"), &
    1903              :                                    drho_cutoff=gradient_cut, &
    1904           36 :                                    tau_cutoff=section_get_rval(xc_section, "TAU_CUTOFF"))
    1905              : 
    1906           36 :             xc_fun_section => section_vals_get_subs_vals(xc_section, "XC_FUNCTIONAL")
    1907           36 :             needs = xc_functionals_get_needs(xc_fun_section, lsd, .TRUE.)
    1908              : 
    1909              :             ! calculate the arguments needed by the functionals
    1910              :             CALL xc_rho_set_update(rho1_set, rho1_r, rho1_g, tau1_r, needs, &
    1911              :                                    section_get_ival(xc_section, "XC_GRID%XC_DERIV"), &
    1912              :                                    section_get_ival(xc_section, "XC_GRID%XC_SMOOTH_RHO"), &
    1913           36 :                                    pw_pool)
    1914              : 
    1915           36 :             IF (lsd) THEN
    1916              :                CALL xc_rho_set_get(rho_set, drhoa=drhoa, drhob=drhob, norm_drho=norm_drho, &
    1917              :                                    norm_drhoa=norm_drhoa, norm_drhob=norm_drhob, tau_a=tau_a, tau_b=tau_b, &
    1918           10 :                                    laplace_rhoa=laplacea, laplace_rhob=laplaceb, can_return_null=.TRUE.)
    1919              :                CALL xc_rho_set_get(rho1_set, rhoa=rho1a, rhob=rho1b, drhoa=drho1a, drhob=drho1b, laplace_rhoa=laplace1a, &
    1920           10 :                                    laplace_rhob=laplace1b, can_return_null=.TRUE.)
    1921              : 
    1922           10 :                CALL calc_drho_from_ab(drho, drhoa, drhob)
    1923           10 :                CALL calc_drho_from_ab(drho1, drho1a, drho1b)
    1924              :             ELSE
    1925           26 :                CALL xc_rho_set_get(rho_set, drho=drho, norm_drho=norm_drho, tau=tau, laplace_rho=laplace, can_return_null=.TRUE.)
    1926           26 :                CALL xc_rho_set_get(rho1_set, rho=rho1, drho=drho1, laplace_rho=laplace1, can_return_null=.TRUE.)
    1927              :             END IF
    1928              : 
    1929           36 :             CALL prepare_dr1dr(dr1dr, drho, drho1)
    1930              : 
    1931           36 :             IF (lsd) THEN
    1932           10 :                CALL prepare_dr1dr(dra1dra, drhoa, drho1a)
    1933           10 :                CALL prepare_dr1dr(drb1drb, drhob, drho1b)
    1934              : 
    1935           10 :                CALL allocate_pw(v_drho, pw_pool, bo)
    1936           10 :                CALL allocate_pw(v_drhoa, pw_pool, bo)
    1937           10 :                CALL allocate_pw(v_drhob, pw_pool, bo)
    1938              : 
    1939           10 :                IF (ASSOCIATED(norm_drhoa)) CALL apply_drho(deriv_set, [deriv_norm_drhoa], virial_pw, drhoa, drho1a, virial_xc, &
    1940           10 :                                                            norm_drhoa, gradient_cut, dra1dra, v_drhoa%array)
    1941           10 :                IF (ASSOCIATED(norm_drhob)) CALL apply_drho(deriv_set, [deriv_norm_drhob], virial_pw, drhob, drho1b, virial_xc, &
    1942           10 :                                                            norm_drhob, gradient_cut, drb1drb, v_drhob%array)
    1943           10 :                IF (ASSOCIATED(norm_drho)) CALL apply_drho(deriv_set, [deriv_norm_drho], virial_pw, drho, drho1, virial_xc, &
    1944            6 :                                                           norm_drho, gradient_cut, dr1dr, v_drho%array)
    1945           10 :                IF (laplace_f) THEN
    1946            2 :                   CALL xc_derivative_get(xc_dset_get_derivative(deriv_set, [deriv_laplace_rhoa]), deriv_data=deriv_data)
    1947            2 :                   CPASSERT(ASSOCIATED(deriv_data))
    1948        15026 :                   virial_pw%array(:, :, :) = -rho1a(:, :, :)
    1949            2 :                   CALL virial_laplace(virial_pw, pw_pool, virial_xc, deriv_data)
    1950              : 
    1951            2 :                   CALL allocate_pw(v_laplacea, pw_pool, bo)
    1952              : 
    1953            2 :                   CALL xc_derivative_get(xc_dset_get_derivative(deriv_set, [deriv_laplace_rhob]), deriv_data=deriv_data)
    1954            2 :                   CPASSERT(ASSOCIATED(deriv_data))
    1955        15026 :                   virial_pw%array(:, :, :) = -rho1b(:, :, :)
    1956            2 :                   CALL virial_laplace(virial_pw, pw_pool, virial_xc, deriv_data)
    1957              : 
    1958            2 :                   CALL allocate_pw(v_laplaceb, pw_pool, bo)
    1959              :                END IF
    1960              : 
    1961              :             ELSE
    1962              : 
    1963              :                ! Create the work grid for the potential of the gradient part
    1964           26 :                CALL allocate_pw(v_drho, pw_pool, bo)
    1965              : 
    1966              :                CALL apply_drho(deriv_set, [deriv_norm_drho], virial_pw, drho, drho1, virial_xc, &
    1967           26 :                                norm_drho, gradient_cut, dr1dr, v_drho%array)
    1968           26 :                IF (laplace_f) THEN
    1969            2 :                   CALL xc_derivative_get(xc_dset_get_derivative(deriv_set, [deriv_laplace_rho]), deriv_data=deriv_data)
    1970            2 :                   CPASSERT(ASSOCIATED(deriv_data))
    1971        28862 :                   virial_pw%array(:, :, :) = -rho1(:, :, :)
    1972            2 :                   CALL virial_laplace(virial_pw, pw_pool, virial_xc, deriv_data)
    1973              : 
    1974            2 :                   CALL allocate_pw(v_laplace, pw_pool, bo)
    1975              :                END IF
    1976              : 
    1977              :             END IF
    1978              : 
    1979           36 :             IF (lsd) THEN
    1980       150260 :                rho_r(1)%array = rhoa
    1981       150260 :                rho_r(2)%array = rhob
    1982              :             ELSE
    1983       701552 :                rho_r(1)%array = rho
    1984              :             END IF
    1985           36 :             IF (ASSOCIATED(tau1_r)) THEN
    1986            8 :             IF (lsd) THEN
    1987        60104 :                tau_r(1)%array = tau_a
    1988        60104 :                tau_r(2)%array = tau_b
    1989              :             ELSE
    1990       115448 :                tau_r(1)%array = tau
    1991              :             END IF
    1992              :             END IF
    1993              : 
    1994              :             ! Create deriv sets with same densities but different gradients
    1995           36 :             CALL xc_dset_create(deriv_set1, pw_pool)
    1996              : 
    1997           36 :             rho_cutoff = section_get_rval(xc_section, "DENSITY_CUTOFF")
    1998              : 
    1999              :             ! create the place where to store the argument for the functionals
    2000              :             CALL xc_rho_set_create(rho2_set, bo, &
    2001              :                                    rho_cutoff=rho_cutoff, &
    2002              :                                    drho_cutoff=section_get_rval(xc_section, "GRADIENT_CUTOFF"), &
    2003           36 :                                    tau_cutoff=section_get_rval(xc_section, "TAU_CUTOFF"))
    2004              : 
    2005              :             ! calculate the arguments needed by the functionals
    2006              :             CALL xc_rho_set_update(rho2_set, rho_r, rho_g, tau_r, needs, &
    2007              :                                    section_get_ival(xc_section, "XC_GRID%XC_DERIV"), &
    2008              :                                    section_get_ival(xc_section, "XC_GRID%XC_SMOOTH_RHO"), &
    2009           36 :                                    pw_pool)
    2010              : 
    2011           36 :             IF (lsd) THEN
    2012              :                CALL xc_rho_set_get(rho1_set, rhoa=rho1a, rhob=rho1b, tau_a=tau1a, tau_b=tau1b, &
    2013           10 :                                    laplace_rhoa=laplace1a, laplace_rhob=laplace1b, can_return_null=.TRUE.)
    2014              :                CALL xc_rho_set_get(rho2_set, norm_drhoa=norm_drho2a, norm_drhob=norm_drho2b, &
    2015           10 :                                    norm_drho=norm_drho2, laplace_rhoa=laplace2a, laplace_rhob=laplace2b, can_return_null=.TRUE.)
    2016              : 
    2017           64 :                DO istep = -nsteps, nsteps
    2018           54 :                   IF (istep == 0) CYCLE
    2019           44 :                   weight = weights(istep, nsteps)/h
    2020           44 :                   step = REAL(istep, dp)*h
    2021           44 :                   IF (ASSOCIATED(norm_drhoa)) THEN
    2022           44 :                      CALL get_derivs_rho(norm_drho2a, norm_drhoa, step, xc_fun_section, lsd, rho2_set, deriv_set1)
    2023              :                      CALL update_deriv_rho(deriv_set1, [deriv_rhoa], bo, &
    2024           44 :                                            norm_drhoa, gradient_cut, weight, rho1a, v_drhoa%array)
    2025              :                      CALL update_deriv_rho(deriv_set1, [deriv_rhob], bo, &
    2026           44 :                                            norm_drhoa, gradient_cut, weight, rho1b, v_drhoa%array)
    2027              :                      CALL update_deriv_rho(deriv_set1, [deriv_norm_drhoa], bo, &
    2028           44 :                                            norm_drhoa, gradient_cut, weight, dra1dra, v_drhoa%array)
    2029              :                      CALL update_deriv_drho_ab(deriv_set1, [deriv_norm_drhob], bo, &
    2030           44 :                                                norm_drhoa, gradient_cut, weight, dra1dra, drb1drb, v_drhoa%array, v_drhob%array)
    2031              :                      CALL update_deriv_drho_ab(deriv_set1, [deriv_norm_drho], bo, &
    2032           44 :                                                norm_drhoa, gradient_cut, weight, dra1dra, dr1dr, v_drhoa%array, v_drho%array)
    2033           44 :                      IF (tau_f) THEN
    2034              :                         CALL update_deriv_rho(deriv_set1, [deriv_tau_a], bo, &
    2035            8 :                                               norm_drhoa, gradient_cut, weight, tau1a, v_drhoa%array)
    2036              :                         CALL update_deriv_rho(deriv_set1, [deriv_tau_b], bo, &
    2037            8 :                                               norm_drhoa, gradient_cut, weight, tau1b, v_drhoa%array)
    2038              :                      END IF
    2039           44 :                      IF (laplace_f) THEN
    2040              :                         CALL update_deriv_rho(deriv_set1, [deriv_laplace_rhoa], bo, &
    2041            4 :                                               norm_drhoa, gradient_cut, weight, laplace1a, v_drhoa%array)
    2042              :                         CALL update_deriv_rho(deriv_set1, [deriv_laplace_rhob], bo, &
    2043            4 :                                               norm_drhoa, gradient_cut, weight, laplace1b, v_drhoa%array)
    2044              :                      END IF
    2045              :                   END IF
    2046              : 
    2047           44 :                   IF (ASSOCIATED(norm_drhob)) THEN
    2048           44 :                      CALL get_derivs_rho(norm_drho2b, norm_drhob, step, xc_fun_section, lsd, rho2_set, deriv_set1)
    2049              :                      CALL update_deriv_rho(deriv_set1, [deriv_rhoa], bo, &
    2050           44 :                                            norm_drhob, gradient_cut, weight, rho1a, v_drhob%array)
    2051              :                      CALL update_deriv_rho(deriv_set1, [deriv_rhob], bo, &
    2052           44 :                                            norm_drhob, gradient_cut, weight, rho1b, v_drhob%array)
    2053              :                      CALL update_deriv_rho(deriv_set1, [deriv_norm_drhob], bo, &
    2054           44 :                                            norm_drhob, gradient_cut, weight, drb1drb, v_drhob%array)
    2055              :                      CALL update_deriv_drho_ab(deriv_set1, [deriv_norm_drhoa], bo, &
    2056           44 :                                                norm_drhob, gradient_cut, weight, drb1drb, dra1dra, v_drhob%array, v_drhoa%array)
    2057              :                      CALL update_deriv_drho_ab(deriv_set1, [deriv_norm_drho], bo, &
    2058           44 :                                                norm_drhob, gradient_cut, weight, drb1drb, dr1dr, v_drhob%array, v_drho%array)
    2059           44 :                      IF (tau_f) THEN
    2060              :                         CALL update_deriv_rho(deriv_set1, [deriv_tau_a], bo, &
    2061            8 :                                               norm_drhob, gradient_cut, weight, tau1a, v_drhob%array)
    2062              :                         CALL update_deriv_rho(deriv_set1, [deriv_tau_b], bo, &
    2063            8 :                                               norm_drhob, gradient_cut, weight, tau1b, v_drhob%array)
    2064              :                      END IF
    2065           44 :                      IF (laplace_f) THEN
    2066              :                         CALL update_deriv_rho(deriv_set1, [deriv_laplace_rhoa], bo, &
    2067            4 :                                               norm_drhob, gradient_cut, weight, laplace1a, v_drhob%array)
    2068              :                         CALL update_deriv_rho(deriv_set1, [deriv_laplace_rhob], bo, &
    2069            4 :                                               norm_drhob, gradient_cut, weight, laplace1b, v_drhob%array)
    2070              :                      END IF
    2071              :                   END IF
    2072              : 
    2073           44 :                   IF (ASSOCIATED(norm_drho)) THEN
    2074           20 :                      CALL get_derivs_rho(norm_drho2, norm_drho, step, xc_fun_section, lsd, rho2_set, deriv_set1)
    2075              :                      CALL update_deriv_rho(deriv_set1, [deriv_rhoa], bo, &
    2076           20 :                                            norm_drho, gradient_cut, weight, rho1a, v_drho%array)
    2077              :                      CALL update_deriv_rho(deriv_set1, [deriv_rhob], bo, &
    2078           20 :                                            norm_drho, gradient_cut, weight, rho1b, v_drho%array)
    2079              :                      CALL update_deriv_rho(deriv_set1, [deriv_norm_drho], bo, &
    2080           20 :                                            norm_drho, gradient_cut, weight, dr1dr, v_drho%array)
    2081              :                      CALL update_deriv_drho_ab(deriv_set1, [deriv_norm_drhoa], bo, &
    2082           20 :                                                norm_drho, gradient_cut, weight, dr1dr, dra1dra, v_drho%array, v_drhoa%array)
    2083              :                      CALL update_deriv_drho_ab(deriv_set1, [deriv_norm_drhob], bo, &
    2084           20 :                                                norm_drho, gradient_cut, weight, dr1dr, drb1drb, v_drho%array, v_drhob%array)
    2085           20 :                      IF (tau_f) THEN
    2086              :                         CALL update_deriv_rho(deriv_set1, [deriv_tau_a], bo, &
    2087            8 :                                               norm_drho, gradient_cut, weight, tau1a, v_drho%array)
    2088              :                         CALL update_deriv_rho(deriv_set1, [deriv_tau_b], bo, &
    2089            8 :                                               norm_drho, gradient_cut, weight, tau1b, v_drho%array)
    2090              :                      END IF
    2091           20 :                      IF (laplace_f) THEN
    2092              :                         CALL update_deriv_rho(deriv_set1, [deriv_laplace_rhoa], bo, &
    2093            4 :                                               norm_drho, gradient_cut, weight, laplace1a, v_drho%array)
    2094              :                         CALL update_deriv_rho(deriv_set1, [deriv_laplace_rhob], bo, &
    2095            4 :                                               norm_drho, gradient_cut, weight, laplace1b, v_drho%array)
    2096              :                      END IF
    2097              :                   END IF
    2098              : 
    2099           54 :                   IF (laplace_f) THEN
    2100              : 
    2101            4 :                      CALL get_derivs_rho(laplace2a, laplacea, step, xc_fun_section, lsd, rho2_set, deriv_set1)
    2102              : 
    2103              :                      ! Obtain the numerical 2nd derivatives w.r.t. to drho and collect the potential
    2104              :                      CALL update_deriv(deriv_set1, laplacea, rho_cutoff, [deriv_rhoa], bo, &
    2105            4 :                                        weight, rho1a, v_laplacea%array)
    2106              :                      CALL update_deriv(deriv_set1, laplacea, rho_cutoff, [deriv_rhob], bo, &
    2107            4 :                                        weight, rho1b, v_laplacea%array)
    2108            4 :                      IF (ASSOCIATED(norm_drho)) THEN
    2109              :                         CALL update_deriv(deriv_set1, laplacea, rho_cutoff, [deriv_norm_drho], bo, &
    2110            4 :                                           weight, dr1dr, v_laplacea%array)
    2111              :                      END IF
    2112            4 :                      IF (ASSOCIATED(norm_drhoa)) THEN
    2113              :                         CALL update_deriv(deriv_set1, laplacea, rho_cutoff, [deriv_norm_drhoa], bo, &
    2114            4 :                                           weight, dra1dra, v_laplacea%array)
    2115              :                      END IF
    2116            4 :                      IF (ASSOCIATED(norm_drhob)) THEN
    2117              :                         CALL update_deriv(deriv_set1, laplacea, rho_cutoff, [deriv_norm_drhob], bo, &
    2118            4 :                                           weight, drb1drb, v_laplacea%array)
    2119              :                      END IF
    2120              : 
    2121            4 :                      IF (ASSOCIATED(tau1a)) THEN
    2122              :                         CALL update_deriv(deriv_set1, laplacea, rho_cutoff, [deriv_tau_a], bo, &
    2123            4 :                                           weight, tau1a, v_laplacea%array)
    2124              :                      END IF
    2125            4 :                      IF (ASSOCIATED(tau1b)) THEN
    2126              :                         CALL update_deriv(deriv_set1, laplacea, rho_cutoff, [deriv_tau_b], bo, &
    2127            4 :                                           weight, tau1b, v_laplacea%array)
    2128              :                      END IF
    2129              : 
    2130              :                      CALL update_deriv(deriv_set1, laplacea, rho_cutoff, [deriv_laplace_rhoa], bo, &
    2131            4 :                                        weight, laplace1a, v_laplacea%array)
    2132              : 
    2133              :                      CALL update_deriv(deriv_set1, laplacea, rho_cutoff, [deriv_laplace_rhob], bo, &
    2134            4 :                                        weight, laplace1b, v_laplacea%array)
    2135              : 
    2136              :                      ! The same for the beta spin
    2137            4 :                      CALL get_derivs_rho(laplace2b, laplaceb, step, xc_fun_section, lsd, rho2_set, deriv_set1)
    2138              : 
    2139              :                      ! Obtain the numerical 2nd derivatives w.r.t. to drho and collect the potential
    2140              :                      CALL update_deriv(deriv_set1, laplaceb, rho_cutoff, [deriv_rhoa], bo, &
    2141            4 :                                        weight, rho1a, v_laplaceb%array)
    2142              :                      CALL update_deriv(deriv_set1, laplaceb, rho_cutoff, [deriv_rhob], bo, &
    2143            4 :                                        weight, rho1b, v_laplaceb%array)
    2144            4 :                      IF (ASSOCIATED(norm_drho)) THEN
    2145              :                         CALL update_deriv(deriv_set1, laplaceb, rho_cutoff, [deriv_norm_drho], bo, &
    2146            4 :                                           weight, dr1dr, v_laplaceb%array)
    2147              :                      END IF
    2148            4 :                      IF (ASSOCIATED(norm_drhoa)) THEN
    2149              :                         CALL update_deriv(deriv_set1, laplaceb, rho_cutoff, [deriv_norm_drhoa], bo, &
    2150            4 :                                           weight, dra1dra, v_laplaceb%array)
    2151              :                      END IF
    2152            4 :                      IF (ASSOCIATED(norm_drhob)) THEN
    2153              :                         CALL update_deriv(deriv_set1, laplaceb, rho_cutoff, [deriv_norm_drhob], bo, &
    2154            4 :                                           weight, drb1drb, v_laplaceb%array)
    2155              :                      END IF
    2156              : 
    2157            4 :                      IF (tau_f) THEN
    2158              :                         CALL update_deriv(deriv_set1, laplaceb, rho_cutoff, [deriv_tau_a], bo, &
    2159            4 :                                           weight, tau1a, v_laplaceb%array)
    2160              :                         CALL update_deriv(deriv_set1, laplaceb, rho_cutoff, [deriv_tau_b], bo, &
    2161            4 :                                           weight, tau1b, v_laplaceb%array)
    2162              :                      END IF
    2163              : 
    2164              :                      CALL update_deriv(deriv_set1, laplaceb, rho_cutoff, [deriv_laplace_rhoa], bo, &
    2165            4 :                                        weight, laplace1a, v_laplaceb%array)
    2166              : 
    2167              :                      CALL update_deriv(deriv_set1, laplaceb, rho_cutoff, [deriv_laplace_rhob], bo, &
    2168            4 :                                        weight, laplace1b, v_laplaceb%array)
    2169              :                   END IF
    2170              :                END DO
    2171              : 
    2172           10 :                CALL virial_drho_drho(virial_pw, drhoa, v_drhoa, virial_xc)
    2173           10 :                CALL virial_drho_drho(virial_pw, drhob, v_drhob, virial_xc)
    2174           10 :                CALL virial_drho_drho(virial_pw, drho, v_drho, virial_xc)
    2175              : 
    2176           10 :                CALL deallocate_pw(v_drho, pw_pool)
    2177           10 :                CALL deallocate_pw(v_drhoa, pw_pool)
    2178           10 :                CALL deallocate_pw(v_drhob, pw_pool)
    2179              : 
    2180           10 :                IF (laplace_f) THEN
    2181        15026 :                   virial_pw%array(:, :, :) = -rhoa(:, :, :)
    2182            2 :                   CALL virial_laplace(virial_pw, pw_pool, virial_xc, v_laplacea%array)
    2183            2 :                   CALL deallocate_pw(v_laplacea, pw_pool)
    2184              : 
    2185        15026 :                   virial_pw%array(:, :, :) = -rhob(:, :, :)
    2186            2 :                   CALL virial_laplace(virial_pw, pw_pool, virial_xc, v_laplaceb%array)
    2187            2 :                   CALL deallocate_pw(v_laplaceb, pw_pool)
    2188              :                END IF
    2189              : 
    2190           10 :                CALL deallocate_pw(virial_pw, pw_pool)
    2191              : 
    2192           40 :                DO idir = 1, 3
    2193           30 :                   DEALLOCATE (drho(idir)%array)
    2194           40 :                   DEALLOCATE (drho1(idir)%array)
    2195              :                END DO
    2196           10 :                DEALLOCATE (dra1dra, drb1drb)
    2197              : 
    2198              :             ELSE
    2199           26 :                CALL xc_rho_set_get(rho1_set, rho=rho1, tau=tau1, laplace_rho=laplace1, can_return_null=.TRUE.)
    2200           26 :                CALL xc_rho_set_get(rho2_set, norm_drho=norm_drho2, laplace_rho=laplace2, can_return_null=.TRUE.)
    2201              : 
    2202          200 :                DO istep = -nsteps, nsteps
    2203          174 :                   IF (istep == 0) CYCLE
    2204          148 :                   weight = weights(istep, nsteps)/h
    2205          148 :                   step = REAL(istep, dp)*h
    2206          148 :                   CALL get_derivs_rho(norm_drho2, norm_drho, step, xc_fun_section, lsd, rho2_set, deriv_set1)
    2207              : 
    2208              :                   ! Obtain the numerical 2nd derivatives w.r.t. to drho and collect the potential
    2209              :                   CALL update_deriv_rho(deriv_set1, [deriv_rho], bo, &
    2210          148 :                                         norm_drho, gradient_cut, weight, rho1, v_drho%array)
    2211              :                   CALL update_deriv_rho(deriv_set1, [deriv_norm_drho], bo, &
    2212          148 :                                         norm_drho, gradient_cut, weight, dr1dr, v_drho%array)
    2213              : 
    2214          148 :                   IF (tau_f) THEN
    2215              :                      CALL update_deriv_rho(deriv_set1, [deriv_tau], bo, &
    2216           24 :                                            norm_drho, gradient_cut, weight, tau1, v_drho%array)
    2217              :                   END IF
    2218          174 :                   IF (laplace_f) THEN
    2219              :                      CALL update_deriv_rho(deriv_set1, [deriv_laplace_rho], bo, &
    2220           12 :                                            norm_drho, gradient_cut, weight, laplace1, v_drho%array)
    2221              : 
    2222           12 :                      CALL get_derivs_rho(laplace2, laplace, step, xc_fun_section, lsd, rho2_set, deriv_set1)
    2223              : 
    2224              :                      ! Obtain the numerical 2nd derivatives w.r.t. to drho and collect the potential
    2225              :                      CALL update_deriv(deriv_set1, laplace, rho_cutoff, [deriv_rho], bo, &
    2226           12 :                                        weight, rho1, v_laplace%array)
    2227              :                      CALL update_deriv(deriv_set1, laplace, rho_cutoff, [deriv_norm_drho], bo, &
    2228           12 :                                        weight, dr1dr, v_laplace%array)
    2229              : 
    2230           12 :                      IF (tau_f) THEN
    2231              :                         CALL update_deriv(deriv_set1, laplace, rho_cutoff, [deriv_tau], bo, &
    2232           12 :                                           weight, tau1, v_laplace%array)
    2233              :                      END IF
    2234              : 
    2235              :                      CALL update_deriv(deriv_set1, laplace, rho_cutoff, [deriv_laplace_rho], bo, &
    2236           12 :                                        weight, laplace1, v_laplace%array)
    2237              :                   END IF
    2238              :                END DO
    2239              : 
    2240              :                ! Calculate the virial contribution from the potential
    2241           26 :                CALL virial_drho_drho(virial_pw, drho, v_drho, virial_xc)
    2242              : 
    2243           26 :                CALL deallocate_pw(v_drho, pw_pool)
    2244              : 
    2245           26 :                IF (laplace_f) THEN
    2246        28862 :                   virial_pw%array(:, :, :) = -rho(:, :, :)
    2247            2 :                   CALL virial_laplace(virial_pw, pw_pool, virial_xc, v_laplace%array)
    2248            2 :                   CALL deallocate_pw(v_laplace, pw_pool)
    2249              :                END IF
    2250              : 
    2251           26 :                CALL deallocate_pw(virial_pw, pw_pool)
    2252              :             END IF
    2253              : 
    2254              :          END IF
    2255              : 
    2256           36 :          CALL xc_dset_release(deriv_set1)
    2257              : 
    2258           36 :          DEALLOCATE (dr1dr)
    2259              : 
    2260           36 :          CALL xc_rho_set_release(rho1_set)
    2261           36 :          CALL xc_rho_set_release(rho2_set)
    2262              :       END IF
    2263              : 
    2264          848 :       DO ispin = 1, SIZE(rho_r)
    2265          848 :          CALL pw_pool%give_back_pw(rho_r(ispin))
    2266              :       END DO
    2267          340 :       DEALLOCATE (rho_r)
    2268              : 
    2269          340 :       IF (ASSOCIATED(tau_r)) THEN
    2270          254 :       DO ispin = 1, SIZE(tau_r)
    2271          254 :          CALL pw_pool%give_back_pw(tau_r(ispin))
    2272              :       END DO
    2273          100 :       DEALLOCATE (tau_r)
    2274              :       END IF
    2275              : 
    2276          340 :       CALL timestop(handle)
    2277              : 
    2278        15300 :    END SUBROUTINE xc_calc_2nd_deriv_numerical
    2279              : 
    2280              : ! **************************************************************************************************
    2281              : !> \brief ...
    2282              : !> \param rho_r ...
    2283              : !> \param rho_g ...
    2284              : !> \param rho1_r ...
    2285              : !> \param rhoa ...
    2286              : !> \param rhob ...
    2287              : !> \param vxc_rho ...
    2288              : !> \param tau_r ...
    2289              : !> \param tau1_r ...
    2290              : !> \param tau_a ...
    2291              : !> \param tau_b ...
    2292              : !> \param vxc_tau ...
    2293              : !> \param xc_section ...
    2294              : !> \param pw_pool ...
    2295              : !> \param step ...
    2296              : ! **************************************************************************************************
    2297          792 :    SUBROUTINE calc_resp_potential_numer_ab(rho_r, rho_g, rho1_r, rhoa, rhob, vxc_rho, &
    2298              :                                            tau_r, tau1_r, tau_a, tau_b, vxc_tau, &
    2299              :                                            xc_section, pw_pool, step)
    2300              : 
    2301              :       TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER, INTENT(IN) :: vxc_rho, vxc_tau
    2302              :       TYPE(pw_r3d_rs_type), DIMENSION(:), INTENT(IN)            :: rho1_r
    2303              :       TYPE(pw_r3d_rs_type), DIMENSION(:), INTENT(IN), POINTER   :: tau1_r
    2304              :       TYPE(pw_pool_type), INTENT(IN), POINTER            :: pw_pool
    2305              :       TYPE(section_vals_type), INTENT(IN), POINTER       :: xc_section
    2306              :       REAL(KIND=dp), INTENT(IN)                          :: step
    2307              :       REAL(KIND=dp), DIMENSION(:, :, :), POINTER, INTENT(IN) :: rhoa, rhob, tau_a, tau_b
    2308              :       TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER, INTENT(IN)   :: rho_r
    2309              :       TYPE(pw_c1d_gs_type), DIMENSION(:), POINTER :: rho_g
    2310              :       TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER               ::  tau_r
    2311              : 
    2312              :       CHARACTER(len=*), PARAMETER :: routineN = 'calc_resp_potential_numer_ab'
    2313              : 
    2314              :       INTEGER                                            :: handle
    2315              :       REAL(KIND=dp)                                      :: exc
    2316              :       REAL(KIND=dp), DIMENSION(3, 3)                     :: virial_dummy
    2317              : 
    2318          792 :       CALL timeset(routineN, handle)
    2319              : 
    2320          792 : !$OMP PARALLEL DEFAULT(NONE) SHARED(rho_r,rhoa,rhob,step,rho1_r,tau_r,tau_a,tau_b,tau1_r)
    2321              : !$OMP WORKSHARE
    2322              :       rho_r(1)%array(:, :, :) = rhoa(:, :, :) + step*rho1_r(1)%array(:, :, :)
    2323              : !$OMP END WORKSHARE NOWAIT
    2324              : !$OMP WORKSHARE
    2325              :       rho_r(2)%array(:, :, :) = rhob(:, :, :) + step*rho1_r(2)%array(:, :, :)
    2326              : !$OMP END WORKSHARE NOWAIT
    2327              :       IF (ASSOCIATED(tau1_r) .AND. ASSOCIATED(tau_r) .AND. ASSOCIATED(tau_a) .AND. ASSOCIATED(tau_b)) THEN
    2328              : !$OMP WORKSHARE
    2329              :          tau_r(1)%array(:, :, :) = tau_a(:, :, :) + step*tau1_r(1)%array(:, :, :)
    2330              : !$OMP END WORKSHARE NOWAIT
    2331              : !$OMP WORKSHARE
    2332              :          tau_r(2)%array(:, :, :) = tau_b(:, :, :) + step*tau1_r(2)%array(:, :, :)
    2333              : !$OMP END WORKSHARE NOWAIT
    2334              :       END IF
    2335              : !$OMP END PARALLEL
    2336              :       CALL xc_vxc_pw_create(vxc_rho, vxc_tau, exc, rho_r, rho_g, tau_r, xc_section, &
    2337          792 :                             pw_pool, .FALSE., virial_dummy)
    2338              : 
    2339          792 :       CALL timestop(handle)
    2340              : 
    2341          792 :    END SUBROUTINE calc_resp_potential_numer_ab
    2342              : 
    2343              : ! **************************************************************************************************
    2344              : !> \brief calculates stress tensor and potential contributions from the first derivative
    2345              : !> \param deriv_set ...
    2346              : !> \param description ...
    2347              : !> \param virial_pw ...
    2348              : !> \param drho ...
    2349              : !> \param drho1 ...
    2350              : !> \param virial_xc ...
    2351              : !> \param norm_drho ...
    2352              : !> \param gradient_cut ...
    2353              : !> \param dr1dr ...
    2354              : !> \param v_drho ...
    2355              : ! **************************************************************************************************
    2356           52 :    SUBROUTINE apply_drho(deriv_set, description, virial_pw, drho, drho1, virial_xc, norm_drho, gradient_cut, dr1dr, v_drho)
    2357              : 
    2358              :       TYPE(xc_derivative_set_type), INTENT(IN)           :: deriv_set
    2359              :       INTEGER, DIMENSION(:), INTENT(in)                  :: description
    2360              :       TYPE(pw_r3d_rs_type), INTENT(IN)                          :: virial_pw
    2361              :       TYPE(cp_3d_r_cp_type), DIMENSION(3), INTENT(IN)     :: drho, drho1
    2362              :       REAL(KIND=dp), DIMENSION(3, 3), INTENT(INOUT)      :: virial_xc
    2363              :       REAL(KIND=dp), DIMENSION(:, :, :), INTENT(IN)      :: norm_drho
    2364              :       REAL(KIND=dp), INTENT(IN)                          :: gradient_cut
    2365              :       REAL(KIND=dp), DIMENSION(:, :, :), INTENT(IN)      :: dr1dr
    2366              :       REAL(KIND=dp), DIMENSION(:, :, :), INTENT(INOUT)   :: v_drho
    2367              : 
    2368              :       CHARACTER(len=*), PARAMETER :: routineN = 'apply_drho'
    2369              : 
    2370              :       INTEGER                                            :: handle
    2371           52 :       REAL(KIND=dp), DIMENSION(:, :, :), POINTER         :: deriv_data
    2372              :       TYPE(xc_derivative_type), POINTER                  :: deriv_att
    2373              : 
    2374           52 :       CALL timeset(routineN, handle)
    2375              : 
    2376           52 :       deriv_att => xc_dset_get_derivative(deriv_set, description)
    2377           52 :       IF (ASSOCIATED(deriv_att)) THEN
    2378           52 :          CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
    2379           52 :          CALL virial_drho_drho1(virial_pw, drho, drho1, deriv_data, virial_xc)
    2380              : 
    2381           52 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(dr1dr,gradient_cut,norm_drho,v_drho,deriv_data)
    2382              :          v_drho(:, :, :) = v_drho(:, :, :) + &
    2383              :                            deriv_data(:, :, :)*dr1dr(:, :, :)/MAX(gradient_cut, norm_drho(:, :, :))**2
    2384              : !$OMP END PARALLEL WORKSHARE
    2385              :       END IF
    2386              : 
    2387           52 :       CALL timestop(handle)
    2388              : 
    2389           52 :    END SUBROUTINE apply_drho
    2390              : 
    2391              : ! **************************************************************************************************
    2392              : !> \brief adds potential contributions from derivatives of rho or diagonal terms of norm_drho
    2393              : !> \param deriv_set1 ...
    2394              : !> \param description ...
    2395              : !> \param bo ...
    2396              : !> \param norm_drho norm_drho of which derivative is calculated
    2397              : !> \param gradient_cut ...
    2398              : !> \param h ...
    2399              : !> \param rho1 function to contract the derivative with (rho1 for rho, dr1dr for norm_drho)
    2400              : !> \param v_drho ...
    2401              : ! **************************************************************************************************
    2402          728 :    SUBROUTINE update_deriv_rho(deriv_set1, description, bo, norm_drho, gradient_cut, weight, rho1, v_drho)
    2403              : 
    2404              :       TYPE(xc_derivative_set_type), INTENT(IN)           :: deriv_set1
    2405              :       INTEGER, DIMENSION(:), INTENT(in)                  :: description
    2406              :       INTEGER, DIMENSION(2, 3), INTENT(IN)               :: bo
    2407              :       REAL(KIND=dp), DIMENSION(bo(1, 1):bo(2, 1), bo(1, &
    2408              :                                                      2):bo(2, 2), bo(1, 3):bo(2, 3)), INTENT(IN)     :: norm_drho
    2409              :       REAL(KIND=dp), INTENT(IN)                          :: gradient_cut, weight
    2410              :       REAL(KIND=dp), DIMENSION(bo(1, 1):bo(2, 1), bo(1, &
    2411              :                                                      2):bo(2, 2), bo(1, 3):bo(2, 3)), INTENT(IN)     :: rho1
    2412              :       REAL(KIND=dp), DIMENSION(bo(1, 1):bo(2, 1), bo(1, &
    2413              :                                                      2):bo(2, 2), bo(1, 3):bo(2, 3)), INTENT(INOUT)  :: v_drho
    2414              : 
    2415              :       CHARACTER(len=*), PARAMETER :: routineN = 'update_deriv_rho'
    2416              : 
    2417              :       INTEGER                                            :: handle, i, j, k
    2418              :       REAL(KIND=dp)                                      :: de
    2419          728 :       REAL(KIND=dp), DIMENSION(:, :, :), POINTER         :: deriv_data1
    2420              :       TYPE(xc_derivative_type), POINTER                  :: deriv_att1
    2421              : 
    2422          728 :       CALL timeset(routineN, handle)
    2423              : 
    2424              :       ! Obtain the numerical 2nd derivatives w.r.t. to drho and collect the potential
    2425          728 :       deriv_att1 => xc_dset_get_derivative(deriv_set1, description)
    2426          728 :       IF (ASSOCIATED(deriv_att1)) THEN
    2427          728 :          CALL xc_derivative_get(deriv_att1, deriv_data=deriv_data1)
    2428              : !$OMP PARALLEL DO DEFAULT(NONE) &
    2429              : !$OMP             SHARED(bo,deriv_data1,weight,norm_drho,v_drho,rho1,gradient_cut) &
    2430              : !$OMP             PRIVATE(i,j,k,de) &
    2431          728 : !$OMP             COLLAPSE(3)
    2432              :          DO k = bo(1, 3), bo(2, 3)
    2433              :             DO j = bo(1, 2), bo(2, 2)
    2434              :                DO i = bo(1, 1), bo(2, 1)
    2435              :                   de = weight*deriv_data1(i, j, k)/MAX(gradient_cut, norm_drho(i, j, k))**2
    2436              :                   v_drho(i, j, k) = v_drho(i, j, k) - de*rho1(i, j, k)
    2437              :                END DO
    2438              :             END DO
    2439              :          END DO
    2440              : !$OMP END PARALLEL DO
    2441              :       END IF
    2442              : 
    2443          728 :       CALL timestop(handle)
    2444              : 
    2445          728 :    END SUBROUTINE update_deriv_rho
    2446              : 
    2447              : ! **************************************************************************************************
    2448              : !> \brief adds potential contributions from derivatives of a component with positive and negative values
    2449              : !> \param deriv_set1 ...
    2450              : !> \param description ...
    2451              : !> \param bo ...
    2452              : !> \param h ...
    2453              : !> \param rho1 function to contract the derivative with (rho1 for rho, dr1dr for norm_drho)
    2454              : !> \param v ...
    2455              : ! **************************************************************************************************
    2456          120 :    SUBROUTINE update_deriv(deriv_set1, rho, rho_cutoff, description, bo, weight, rho1, v)
    2457              : 
    2458              :       TYPE(xc_derivative_set_type), INTENT(IN)           :: deriv_set1
    2459              :       INTEGER, DIMENSION(:), INTENT(in)                  :: description
    2460              :       INTEGER, DIMENSION(2, 3), INTENT(IN)               :: bo
    2461              :       REAL(KIND=dp), INTENT(IN)                          :: weight, rho_cutoff
    2462              :       REAL(KIND=dp), DIMENSION(bo(1, 1):bo(2, 1), bo(1, &
    2463              :                                                      2):bo(2, 2), bo(1, 3):bo(2, 3)), INTENT(IN)     :: rho, rho1
    2464              :       REAL(KIND=dp), DIMENSION(bo(1, 1):bo(2, 1), bo(1, &
    2465              :                                                      2):bo(2, 2), bo(1, 3):bo(2, 3)), INTENT(INOUT)  :: v
    2466              : 
    2467              :       CHARACTER(len=*), PARAMETER :: routineN = 'update_deriv'
    2468              : 
    2469              :       INTEGER                                            :: handle, i, j, k
    2470              :       REAL(KIND=dp)                                      :: de
    2471          120 :       REAL(KIND=dp), DIMENSION(:, :, :), POINTER         :: deriv_data1
    2472              :       TYPE(xc_derivative_type), POINTER                  :: deriv_att1
    2473              : 
    2474          120 :       CALL timeset(routineN, handle)
    2475              : 
    2476              :       ! Obtain the numerical 2nd derivatives w.r.t. to drho and collect the potential
    2477          120 :       deriv_att1 => xc_dset_get_derivative(deriv_set1, description)
    2478          120 :       IF (ASSOCIATED(deriv_att1)) THEN
    2479          120 :          CALL xc_derivative_get(deriv_att1, deriv_data=deriv_data1)
    2480              : !$OMP PARALLEL DO DEFAULT(NONE) &
    2481              : !$OMP             SHARED(bo,deriv_data1,weight,v,rho1,rho, rho_cutoff) &
    2482              : !$OMP             PRIVATE(i,j,k,de) &
    2483          120 : !$OMP             COLLAPSE(3)
    2484              :          DO k = bo(1, 3), bo(2, 3)
    2485              :             DO j = bo(1, 2), bo(2, 2)
    2486              :                DO i = bo(1, 1), bo(2, 1)
    2487              :                   ! We have to consider that the given density (mostly the Laplacian) may have positive and negative values
    2488              :                   de = weight*deriv_data1(i, j, k)/SIGN(MAX(ABS(rho(i, j, k)), rho_cutoff), rho(i, j, k))
    2489              :                   v(i, j, k) = v(i, j, k) + de*rho1(i, j, k)
    2490              :                END DO
    2491              :             END DO
    2492              :          END DO
    2493              : !$OMP END PARALLEL DO
    2494              :       END IF
    2495              : 
    2496          120 :       CALL timestop(handle)
    2497              : 
    2498          120 :    END SUBROUTINE update_deriv
    2499              : 
    2500              : ! **************************************************************************************************
    2501              : !> \brief adds mixed derivatives of norm_drho
    2502              : !> \param deriv_set1 ...
    2503              : !> \param description ...
    2504              : !> \param bo ...
    2505              : !> \param norm_drhoa norm_drho of which derivatives is calculated
    2506              : !> \param gradient_cut ...
    2507              : !> \param h ...
    2508              : !> \param dra1dra dr1dr corresponding to norm_drho
    2509              : !> \param drb1drb ...
    2510              : !> \param v_drhoa potential corresponding to norm_drho
    2511              : !> \param v_drhob ...
    2512              : ! **************************************************************************************************
    2513          216 :    SUBROUTINE update_deriv_drho_ab(deriv_set1, description, bo, &
    2514          216 :                                    norm_drhoa, gradient_cut, weight, dra1dra, drb1drb, v_drhoa, v_drhob)
    2515              : 
    2516              :       TYPE(xc_derivative_set_type), INTENT(IN)           :: deriv_set1
    2517              :       INTEGER, DIMENSION(:), INTENT(in)                  :: description
    2518              :       INTEGER, DIMENSION(2, 3), INTENT(IN)               :: bo
    2519              :       REAL(KIND=dp), DIMENSION(bo(1, 1):bo(2, 1), bo(1, &
    2520              :                                                      2):bo(2, 2), bo(1, 3):bo(2, 3)), INTENT(IN)     :: norm_drhoa
    2521              :       REAL(KIND=dp), INTENT(IN)                          :: gradient_cut, weight
    2522              :       REAL(KIND=dp), DIMENSION(bo(1, 1):bo(2, 1), bo(1, &
    2523              :                                                      2):bo(2, 2), bo(1, 3):bo(2, 3)), INTENT(IN)     :: dra1dra, drb1drb
    2524              :       REAL(KIND=dp), DIMENSION(bo(1, 1):bo(2, 1), bo(1, &
    2525              :                                                      2):bo(2, 2), bo(1, 3):bo(2, 3)), INTENT(INOUT)  :: v_drhoa, v_drhob
    2526              : 
    2527              :       CHARACTER(len=*), PARAMETER :: routineN = 'update_deriv_drho_ab'
    2528              : 
    2529              :       INTEGER                                            :: handle, i, j, k
    2530              :       REAL(KIND=dp)                                      :: de
    2531          216 :       REAL(KIND=dp), DIMENSION(:, :, :), POINTER         :: deriv_data1
    2532              :       TYPE(xc_derivative_type), POINTER                  :: deriv_att1
    2533              : 
    2534          216 :       CALL timeset(routineN, handle)
    2535              : 
    2536          216 :       deriv_att1 => xc_dset_get_derivative(deriv_set1, description)
    2537          216 :       IF (ASSOCIATED(deriv_att1)) THEN
    2538          168 :          CALL xc_derivative_get(deriv_att1, deriv_data=deriv_data1)
    2539              : !$OMP PARALLEL DO DEFAULT(NONE) &
    2540              : !$OMP             PRIVATE(k,j,i,de) &
    2541              : !$OMP             SHARED(bo,drb1drb,dra1dra,deriv_data1,weight,gradient_cut,norm_drhoa,v_drhoa,v_drhob) &
    2542          168 : !$OMP             COLLAPSE(3)
    2543              :          DO k = bo(1, 3), bo(2, 3)
    2544              :             DO j = bo(1, 2), bo(2, 2)
    2545              :                DO i = bo(1, 1), bo(2, 1)
    2546              :                   ! We introduce a factor of two because we will average between both numerical derivatives
    2547              :                   de = 0.5_dp*weight*deriv_data1(i, j, k)/MAX(gradient_cut, norm_drhoa(i, j, k))**2
    2548              :                   v_drhoa(i, j, k) = v_drhoa(i, j, k) - de*drb1drb(i, j, k)
    2549              :                   v_drhob(i, j, k) = v_drhob(i, j, k) - de*dra1dra(i, j, k)
    2550              :                END DO
    2551              :             END DO
    2552              :          END DO
    2553              : !$OMP END PARALLEL DO
    2554              :       END IF
    2555              : 
    2556          216 :       CALL timestop(handle)
    2557              : 
    2558          216 :    END SUBROUTINE update_deriv_drho_ab
    2559              : 
    2560              : ! **************************************************************************************************
    2561              : !> \brief calculate derivative sets for helper points
    2562              : !> \param norm_drho2 norm_drho of new points
    2563              : !> \param norm_drho norm_drho of KS density
    2564              : !> \param h ...
    2565              : !> \param xc_fun_section ...
    2566              : !> \param lsd ...
    2567              : !> \param rho2_set rho_set for new points
    2568              : !> \param deriv_set1 will contain derivatives of the perturbed density
    2569              : ! **************************************************************************************************
    2570          276 :    SUBROUTINE get_derivs_rho(norm_drho2, norm_drho, step, xc_fun_section, lsd, rho2_set, deriv_set1)
    2571              :       REAL(KIND=dp), DIMENSION(:, :, :), INTENT(OUT)     :: norm_drho2
    2572              :       REAL(KIND=dp), DIMENSION(:, :, :), INTENT(IN)      :: norm_drho
    2573              :       REAL(KIND=dp), INTENT(IN)                          :: step
    2574              :       TYPE(section_vals_type), INTENT(IN), POINTER       :: xc_fun_section
    2575              :       LOGICAL, INTENT(IN)                                :: lsd
    2576              :       TYPE(xc_rho_set_type), INTENT(INOUT)               :: rho2_set
    2577              :       TYPE(xc_derivative_set_type)                       :: deriv_set1
    2578              : 
    2579              :       CHARACTER(len=*), PARAMETER :: routineN = 'get_derivs_rho'
    2580              : 
    2581              :       INTEGER                                            :: handle
    2582              : 
    2583          276 :       CALL timeset(routineN, handle)
    2584              : 
    2585              :       ! Copy the densities, do one step into the direction of drho
    2586          276 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(norm_drho,norm_drho2,step)
    2587              :       norm_drho2 = norm_drho*(1.0_dp + step)
    2588              : !$OMP END PARALLEL WORKSHARE
    2589              : 
    2590          276 :       CALL xc_dset_zero_all(deriv_set1)
    2591              : 
    2592              :       ! Calculate the derivatives of the functional
    2593              :       CALL xc_functionals_eval(xc_fun_section, &
    2594              :                                lsd=lsd, &
    2595              :                                rho_set=rho2_set, &
    2596              :                                deriv_set=deriv_set1, &
    2597          276 :                                deriv_order=1)
    2598              : 
    2599              :       ! Return to the original values
    2600          276 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(norm_drho,norm_drho2)
    2601              :       norm_drho2 = norm_drho
    2602              : !$OMP END PARALLEL WORKSHARE
    2603              : 
    2604          276 :       CALL divide_by_norm_drho(deriv_set1, rho2_set, lsd)
    2605              : 
    2606          276 :       CALL timestop(handle)
    2607              : 
    2608          276 :    END SUBROUTINE get_derivs_rho
    2609              : 
    2610              : ! **************************************************************************************************
    2611              : !> \brief Calculates the second derivative of E_xc at rho in the direction
    2612              : !>      rho1  (if you see the second derivative as bilinear form)
    2613              : !>      partial_rho|_(rho=rho) partial_rho|_(rho=rho) E_xc drho(rho1)drho
    2614              : !>      The other direction is still undetermined, thus it returns
    2615              : !>      a potential (partial integration is performed to reduce it to
    2616              : !>      function of rho, removing the dependence from its partial derivs)
    2617              : !>      Has to be called after the setup by xc_prep_2nd_deriv.
    2618              : !> \param v_xc       exchange-correlation potential
    2619              : !> \param v_xc_tau ...
    2620              : !> \param deriv_set  derivatives of the exchange-correlation potential
    2621              : !> \param rho_set    object containing the density at which the derivatives were calculated
    2622              : !> \param rho1_set   object containing the density with which to fold
    2623              : !> \param pw_pool    the pool for the grids
    2624              : !> \param xc_section XC parameters
    2625              : !> \param gapw       Gaussian and augmented plane waves calculation
    2626              : !> \param vxg ...
    2627              : !> \param tddfpt_fac factor that multiplies the crossterms (tddfpt triplets
    2628              : !>        on a closed shell system it should be -1, defaults to 1)
    2629              : !> \param compute_virial ...
    2630              : !> \param virial_xc ...
    2631              : !> \note
    2632              : !>      The old version of this routine was smarter: it handled split_desc(1)
    2633              : !>      and split_desc(2) separately, thus the code automatically handled all
    2634              : !>      possible cross terms (you only had to check if it was diagonal to avoid
    2635              : !>      double counting). I think that is the way to go if you want to add more
    2636              : !>      terms (tau,rho in LSD,...). The problem with the old code was that it
    2637              : !>      because of the old functional structure it sometime guessed wrongly
    2638              : !>      which derivative was where. There were probably still bugs with gradient
    2639              : !>      corrected functionals (never tested), and it didn't contain first
    2640              : !>      derivatives with respect to drho (that contribute also to the second
    2641              : !>      derivative wrt. rho).
    2642              : !>      The code was a little complex because it really tried to handle any
    2643              : !>      functional derivative in the most efficient way with the given contents of
    2644              : !>      rho_set.
    2645              : !>      Anyway I strongly encourage whoever wants to modify this code to give a
    2646              : !>      look to the old version. [fawzi]
    2647              : ! **************************************************************************************************
    2648        33196 :    SUBROUTINE xc_calc_2nd_deriv_analytical(v_xc, v_xc_tau, deriv_set, rho_set, rho1_set, &
    2649              :                                            pw_pool, xc_section, gapw, vxg, tddfpt_fac, &
    2650              :                                            compute_virial, virial_xc, spinflip)
    2651              : 
    2652              :       TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER             :: v_xc, v_xc_tau
    2653              :       TYPE(xc_derivative_set_type)                       :: deriv_set
    2654              :       TYPE(xc_rho_set_type), INTENT(IN)                  :: rho_set, rho1_set
    2655              :       TYPE(pw_pool_type), POINTER                        :: pw_pool
    2656              :       TYPE(section_vals_type), POINTER                   :: xc_section
    2657              :       LOGICAL, INTENT(IN), OPTIONAL                      :: gapw
    2658              :       REAL(kind=dp), DIMENSION(:, :, :, :), OPTIONAL, &
    2659              :          POINTER                                         :: vxg
    2660              :       REAL(kind=dp), INTENT(in), OPTIONAL                :: tddfpt_fac
    2661              :       LOGICAL, INTENT(IN), OPTIONAL                      :: compute_virial
    2662              :       REAL(KIND=dp), DIMENSION(3, 3), INTENT(INOUT), &
    2663              :          OPTIONAL                                        :: virial_xc
    2664              :       LOGICAL, INTENT(in), OPTIONAL                      :: spinflip
    2665              : 
    2666              :       CHARACTER(len=*), PARAMETER :: routineN = 'xc_calc_2nd_deriv_analytical'
    2667              : 
    2668              :       INTEGER                                            :: handle, i, ia, idir, ir, ispin, j, jdir, &
    2669              :                                                             k, nspins, xc_deriv_method_id
    2670              :       INTEGER, DIMENSION(2, 3)                           :: bo
    2671              :       LOGICAL                                            :: gradient_f, lsd, my_compute_virial, alda0, &
    2672              :                                                             my_gapw, tau_f, laplace_f, rho_f, do_spinflip
    2673              :       REAL(KIND=dp)                                      :: fac, gradient_cut, tmp, factor2, s, S_THRESH
    2674        33196 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: dr1dr, dra1dra, drb1drb
    2675        33196 :       REAL(kind=dp), DIMENSION(:, :, :), POINTER         :: deriv_data, deriv_data2, &
    2676        33196 :                                                             e_drhoa, e_drhob, e_drho, norm_drho, norm_drhoa, &
    2677        33196 :                                                             norm_drhob, rho1, rho1a, rho1b, &
    2678        33196 :                                                             tau1, tau1a, tau1b, laplace1, laplace1a, laplace1b, &
    2679        33196 :                                                             rho, rhoa, rhob
    2680       630724 :       TYPE(cp_3d_r_cp_type), DIMENSION(3)                :: drho, drho1, drho1a, drho1b, drhoa, drhob
    2681        33196 :       TYPE(pw_r3d_rs_type), DIMENSION(:), ALLOCATABLE         :: v_drhoa, v_drhob, v_drho, v_laplace
    2682        33196 :       TYPE(pw_r3d_rs_type), DIMENSION(:, :), ALLOCATABLE      :: v_drho_r
    2683              :       TYPE(pw_r3d_rs_type)                                      ::  virial_pw
    2684              :       TYPE(pw_c1d_gs_type) :: tmp_g, vxc_g
    2685              :       TYPE(xc_derivative_type), POINTER                  :: deriv_att
    2686              : 
    2687        33196 :       CALL timeset(routineN, handle)
    2688              : 
    2689        33196 :       NULLIFY (e_drhoa, e_drhob, e_drho)
    2690              : 
    2691        33196 :       my_gapw = .FALSE.
    2692        33196 :       IF (PRESENT(gapw)) my_gapw = gapw
    2693              : 
    2694        33196 :       my_compute_virial = .FALSE.
    2695        33196 :       IF (PRESENT(compute_virial)) my_compute_virial = compute_virial
    2696              : 
    2697        33196 :       CPASSERT(ASSOCIATED(v_xc))
    2698        33196 :       CPASSERT(ASSOCIATED(xc_section))
    2699        33196 :       IF (my_gapw) THEN
    2700        11166 :          CPASSERT(PRESENT(vxg))
    2701              :       END IF
    2702        33196 :       IF (my_compute_virial) THEN
    2703          358 :          CPASSERT(PRESENT(virial_xc))
    2704              :       END IF
    2705              : 
    2706              :       CALL section_vals_val_get(xc_section, "XC_GRID%XC_DERIV", &
    2707        33196 :                                 i_val=xc_deriv_method_id)
    2708        33196 :       CALL xc_rho_set_get(rho_set, drho_cutoff=gradient_cut)
    2709        33196 :       nspins = SIZE(v_xc)
    2710        33196 :       lsd = ASSOCIATED(rho_set%rhoa)
    2711        33196 :       fac = 0.0_dp
    2712        33196 :       factor2 = 1.0_dp
    2713        33196 :       IF (PRESENT(tddfpt_fac)) fac = tddfpt_fac
    2714        33196 :       IF (PRESENT(tddfpt_fac)) factor2 = tddfpt_fac
    2715        33196 :       do_spinflip = .FALSE.
    2716        33196 :       IF (PRESENT(spinflip)) do_spinflip = spinflip
    2717              : 
    2718       331960 :       bo = rho_set%local_bounds
    2719              : 
    2720        33196 :       CALL check_for_derivatives(deriv_set, lsd, rho_f, gradient_f, tau_f, laplace_f)
    2721              : 
    2722        33196 :       alda0 = .false.
    2723        33196 :       IF (gradient_f) THEN
    2724              :          S_THRESH = 1.0E-04
    2725              :       ELSE
    2726        12278 :          S_THRESH = 1.0E-10
    2727              :       END IF
    2728              : 
    2729        33196 :       IF (tau_f) THEN
    2730          656 :          CPASSERT(ASSOCIATED(v_xc_tau))
    2731              :       END IF
    2732              : 
    2733        33196 :       IF (gradient_f) THEN
    2734       219060 :          ALLOCATE (v_drho_r(3, nspins), v_drho(nspins))
    2735        43812 :          DO ispin = 1, nspins
    2736        91576 :             DO idir = 1, 3
    2737        91576 :                CALL allocate_pw(v_drho_r(idir, ispin), pw_pool, bo)
    2738              :             END DO
    2739        43812 :             CALL allocate_pw(v_drho(ispin), pw_pool, bo)
    2740              :          END DO
    2741              : 
    2742        20918 :          IF (xc_requires_tmp_g(xc_deriv_method_id) .AND. .NOT. my_gapw) THEN
    2743        12300 :             IF (ASSOCIATED(pw_pool)) THEN
    2744        12300 :                CALL pw_pool%create_pw(tmp_g)
    2745        12300 :                CALL pw_pool%create_pw(vxc_g)
    2746              :             ELSE
    2747              :                ! remember to refix for gapw
    2748            0 :                CPABORT("XC_DERIV method is not implemented in GAPW")
    2749              :             END IF
    2750              :          END IF
    2751              :       END IF
    2752              : 
    2753        70418 :       DO ispin = 1, nspins
    2754   1065080064 :          v_xc(ispin)%array = 0.0_dp
    2755              :       END DO
    2756              : 
    2757        33196 :       IF (tau_f) THEN
    2758         1386 :          DO ispin = 1, nspins
    2759     14897758 :             v_xc_tau(ispin)%array = 0.0_dp
    2760              :          END DO
    2761              :       END IF
    2762              : 
    2763        33196 :       IF (laplace_f .AND. my_gapw) &
    2764            0 :          CPABORT("Laplace-dependent functional not implemented with GAPW!")
    2765              : 
    2766        33196 :       IF (my_compute_virial .AND. (gradient_f .OR. laplace_f)) CALL allocate_pw(virial_pw, pw_pool, bo)
    2767              : 
    2768        33196 :       IF (lsd) THEN
    2769              : 
    2770              :          !-------------------!
    2771              :          ! UNrestricted case !
    2772              :          !-------------------!
    2773              : 
    2774         5168 :          IF (do_spinflip) THEN
    2775          414 :             CALL xc_rho_set_get(rho1_set, rhoa=rho1a)
    2776          414 :             CALL xc_rho_set_get(rho_set, rhoa=rhoa, rhob=rhob)
    2777              :          ELSE
    2778         4754 :             CALL xc_rho_set_get(rho1_set, rhoa=rho1a, rhob=rho1b)
    2779              :          END IF
    2780              : 
    2781         5168 :          IF (gradient_f) THEN
    2782              :             CALL xc_rho_set_get(rho_set, drhoa=drhoa, drhob=drhob, &
    2783         2738 :                                 norm_drho=norm_drho, norm_drhoa=norm_drhoa, norm_drhob=norm_drhob)
    2784         2738 :             IF (do_spinflip) THEN
    2785          262 :                CALL xc_rho_set_get(rho1_set, drhoa=drho1a)
    2786          262 :                CALL calc_drho_from_a(drho1, drho1a)
    2787              :             ELSE
    2788         2476 :                CALL xc_rho_set_get(rho1_set, drhoa=drho1a, drhob=drho1b)
    2789         2476 :                CALL calc_drho_from_ab(drho1, drho1a, drho1b)
    2790              :             END IF
    2791              : 
    2792         2738 :             CALL calc_drho_from_ab(drho, drhoa, drhob)
    2793              : 
    2794         2738 :             CALL prepare_dr1dr(dra1dra, drhoa, drho1a)
    2795         2738 :             IF (do_spinflip) THEN
    2796          262 :                CALL prepare_dr1dr(drb1drb, drhob, drho1a)
    2797          262 :                CALL prepare_dr1dr(dr1dr, drho, drho1a)
    2798         2476 :             ELSE IF (nspins /= 1) THEN
    2799         1766 :                CALL prepare_dr1dr(drb1drb, drhob, drho1b)
    2800         1766 :                CALL prepare_dr1dr(dr1dr, drho, drho1)
    2801              :             ELSE
    2802          710 :                CALL prepare_dr1dr(drb1drb, drhob, drho1b)
    2803          710 :                CALL prepare_dr1dr_ab(dr1dr, drhoa, drhob, drho1a, drho1b, fac)
    2804              :             END IF
    2805              : 
    2806        20380 :             ALLOCATE (v_drhoa(nspins), v_drhob(nspins))
    2807         7452 :             DO ispin = 1, nspins
    2808         4714 :                CALL allocate_pw(v_drhoa(ispin), pw_pool, bo)
    2809         7452 :                CALL allocate_pw(v_drhob(ispin), pw_pool, bo)
    2810              :             END DO
    2811              : 
    2812              :          END IF
    2813              : 
    2814         5168 :          IF (laplace_f) THEN
    2815           38 :             CALL xc_rho_set_get(rho1_set, laplace_rhoa=laplace1a, laplace_rhob=laplace1b)
    2816              : 
    2817          190 :             ALLOCATE (v_laplace(nspins))
    2818          114 :             DO ispin = 1, nspins
    2819          114 :                CALL allocate_pw(v_laplace(ispin), pw_pool, bo)
    2820              :             END DO
    2821              : 
    2822           38 :             IF (my_compute_virial) CALL xc_rho_set_get(rho_set, rhoa=rhoa, rhob=rhob)
    2823              :          END IF
    2824              : 
    2825         5168 :          IF (tau_f) THEN
    2826           74 :             CALL xc_rho_set_get(rho1_set, tau_a=tau1a, tau_b=tau1b)
    2827              :          END IF
    2828              : 
    2829         5168 :          IF (do_spinflip) THEN
    2830              : 
    2831              :             ! vxc contributions
    2832              :             !   vxc = (vxc^{\alpha}-vxc^{\beta})*rho1/(rhoa-rhob)
    2833              :             !     Alpha LDA contribution
    2834              :             !           | d e_xc     d e_xc |     rho1a
    2835              :             !   vxca =  |-------- - --------|*-------------
    2836              :             !           | drhoa      drhob  | |rhoa - rhob|
    2837          414 :             deriv_att => xc_dset_get_derivative(deriv_set, [deriv_rhoa])
    2838          414 :             IF (ASSOCIATED(deriv_att)) THEN
    2839          414 :                CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
    2840          414 :                deriv_att => xc_dset_get_derivative(deriv_set, [deriv_rhob])
    2841          414 :                IF (ASSOCIATED(deriv_att)) THEN
    2842          414 :                   CALL xc_derivative_get(deriv_att, deriv_data=deriv_data2)
    2843              : !$OMP             PARALLEL DO PRIVATE(k,j,i,s) DEFAULT(NONE)&
    2844          414 : !$OMP             SHARED(bo,v_xc,deriv_data,deriv_data2,rho1a,rhoa,rhob,S_THRESH) COLLAPSE(3)
    2845              :                   DO k = bo(1, 3), bo(2, 3)
    2846              :                      DO j = bo(1, 2), bo(2, 2)
    2847              :                         DO i = bo(1, 1), bo(2, 1)
    2848              :                            s = MAX(ABS(rhoa(i, j, k) - rhob(i, j, k)), S_THRESH)
    2849              :                            v_xc(1)%array(i, j, k) = v_xc(1)%array(i, j, k) + &
    2850              :                                                     (deriv_data(i, j, k) - deriv_data2(i, j, k))*rho1a(i, j, k)/s
    2851              :                         END DO
    2852              :                      END DO
    2853              :                   END DO
    2854              : !$OMP             END PARALLEL DO
    2855              :                END IF
    2856              :             END IF
    2857              :             ! GGA contributions to the spin-flip xcKernel
    2858              :             !    GGA contribution
    2859              :             !            |  d e_xc               d e_xc           |       1
    2860              :             !   vxca +=  |----------* dra1dra - ----------*drb1drb|*-------------
    2861              :             !            | d|drhoa|              d|drhob|         | |rhoa - rhob|
    2862              :             IF (.NOT. alda0) THEN
    2863          414 :                deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drhoa])
    2864          414 :                IF (ASSOCIATED(deriv_att)) THEN
    2865          262 :                   CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
    2866          262 :                   deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drhob])
    2867          262 :                   IF (ASSOCIATED(deriv_att)) THEN
    2868          262 :                      CALL xc_derivative_get(deriv_att, deriv_data=deriv_data2)
    2869              : !$OMP             PARALLEL DO PRIVATE(k,j,i,s) DEFAULT(NONE)&
    2870          262 : !$OMP             SHARED(bo,deriv_data,deriv_data2,dra1dra,drb1drb,v_xc,rhoa,rhob,S_THRESH) COLLAPSE(3)
    2871              :                      DO k = bo(1, 3), bo(2, 3)
    2872              :                         DO j = bo(1, 2), bo(2, 2)
    2873              :                            DO i = bo(1, 1), bo(2, 1)
    2874              :                               s = MAX(ABS(rhoa(i, j, k) - rhob(i, j, k)), S_THRESH)
    2875              :                               v_xc(1)%array(i, j, k) = v_xc(1)%array(i, j, k) + &
    2876              :                                                        (deriv_data(i, j, k)*dra1dra(i, j, k) - &
    2877              :                                                         deriv_data2(i, j, k)*drb1drb(i, j, k))/s
    2878              :                            END DO
    2879              :                         END DO
    2880              :                      END DO
    2881              : !$OMP             END PARALLEL DO
    2882              :                   END IF
    2883              :                END IF
    2884              :             END IF
    2885              : 
    2886         4754 :          ELSE IF (nspins /= 1) THEN
    2887              : 
    2888              :             ! Compute \sum_{\tau}fxc^{\sigma\tau}*\rho^{\tau}(1) over the grid points
    2889        33764 :             $:add_2nd_derivative_terms(arguments_openshell)
    2890              : 
    2891              :          ELSE
    2892              : 
    2893              :             ! Compute (fxc^{\alpha\alpha}+-fxc^{\beta\beta})*\rho(1) over the grid points
    2894         1038 :             $:add_2nd_derivative_terms(arguments_triplet_outer, arguments_triplet_inner)
    2895              : 
    2896              :          END IF
    2897              : 
    2898         5168 :          IF (gradient_f) THEN
    2899         2738 :             IF (.NOT. do_spinflip) THEN
    2900              : 
    2901         2476 :                IF (my_compute_virial) THEN
    2902           10 :                   CALL virial_drho_drho(virial_pw, drhoa, v_drhoa(1), virial_xc)
    2903           10 :                   CALL virial_drho_drho(virial_pw, drhob, v_drhob(2), virial_xc)
    2904           40 :                   DO idir = 1, 3
    2905           30 : !$OMP                PARALLEL WORKSHARE DEFAULT(NONE) SHARED(drho,idir,v_drho,virial_pw)
    2906              :                      virial_pw%array(:, :, :) = drho(idir)%array(:, :, :)*(v_drho(1)%array(:, :, :) + v_drho(2)%array(:, :, :))
    2907              : !$OMP                END PARALLEL WORKSHARE
    2908          100 :                      DO jdir = 1, idir
    2909              :                         tmp = -0.5_dp*virial_pw%pw_grid%dvol*accurate_dot_product(virial_pw%array(:, :, :), &
    2910           60 :                                                                                   drho(jdir)%array(:, :, :))
    2911           60 :                         virial_xc(jdir, idir) = virial_xc(jdir, idir) + tmp
    2912           90 :                         virial_xc(idir, jdir) = virial_xc(jdir, idir)
    2913              :                      END DO
    2914              :                   END DO
    2915              :                END IF ! my_compute_virial
    2916              : 
    2917         2476 :                IF (my_gapw) THEN
    2918              : !$OMP PARALLEL DO DEFAULT(NONE) &
    2919              : !$OMP             PRIVATE(ia,idir,ispin,ir) &
    2920              : !$OMP             SHARED(bo,nspins,vxg,drhoa,drhob,v_drhoa,v_drhob,v_drho, &
    2921          764 : !$OMP                   e_drhoa,e_drhob,e_drho,drho1a,drho1b,fac,drho,drho1) COLLAPSE(3)
    2922              :                   DO ir = bo(1, 2), bo(2, 2)
    2923              :                      DO ia = bo(1, 1), bo(2, 1)
    2924              :                         DO idir = 1, 3
    2925              :                            DO ispin = 1, nspins
    2926              :                               vxg(idir, ia, ir, ispin) = &
    2927              :                                  -(v_drhoa(ispin)%array(ia, ir, 1)*drhoa(idir)%array(ia, ir, 1) + &
    2928              :                                    v_drhob(ispin)%array(ia, ir, 1)*drhob(idir)%array(ia, ir, 1) + &
    2929              :                                    v_drho(ispin)%array(ia, ir, 1)*drho(idir)%array(ia, ir, 1))
    2930              :                            END DO
    2931              :                            IF (ASSOCIATED(e_drhoa)) THEN
    2932              :                               vxg(idir, ia, ir, 1) = vxg(idir, ia, ir, 1) + &
    2933              :                                                      e_drhoa(ia, ir, 1)*drho1a(idir)%array(ia, ir, 1)
    2934              :                            END IF
    2935              :                            IF (nspins /= 1 .AND. ASSOCIATED(e_drhob)) THEN
    2936              :                               vxg(idir, ia, ir, 2) = vxg(idir, ia, ir, 2) + &
    2937              :                                                      e_drhob(ia, ir, 1)*drho1b(idir)%array(ia, ir, 1)
    2938              :                            END IF
    2939              :                            IF (ASSOCIATED(e_drho)) THEN
    2940              :                               IF (nspins /= 1) THEN
    2941              :                                  vxg(idir, ia, ir, 1) = vxg(idir, ia, ir, 1) + &
    2942              :                                                         e_drho(ia, ir, 1)*drho1(idir)%array(ia, ir, 1)
    2943              :                                  vxg(idir, ia, ir, 2) = vxg(idir, ia, ir, 2) + &
    2944              :                                                         e_drho(ia, ir, 1)*drho1(idir)%array(ia, ir, 1)
    2945              :                               ELSE
    2946              :                                  vxg(idir, ia, ir, 1) = vxg(idir, ia, ir, 1) + &
    2947              :                                                         e_drho(ia, ir, 1)*(drho1a(idir)%array(ia, ir, 1) + &
    2948              :                                                                            fac*drho1b(idir)%array(ia, ir, 1))
    2949              :                               END IF
    2950              :                            END IF
    2951              :                         END DO
    2952              :                      END DO
    2953              :                   END DO
    2954              : !$OMP END PARALLEL DO
    2955              :                ELSE
    2956              : 
    2957              :                   ! partial integration
    2958         6848 :                   DO idir = 1, 3
    2959              : 
    2960        14466 :                      DO ispin = 1, nspins
    2961              : !$OMP                   PARALLEL WORKSHARE DEFAULT(NONE) &
    2962        14466 : !$OMP                   SHARED(v_drho_r,v_drhoa,v_drhob,v_drho,drhoa,drhob,drho,ispin,idir)
    2963              :                         v_drho_r(idir, ispin)%array(:, :, :) = &
    2964              :                            v_drhoa(ispin)%array(:, :, :)*drhoa(idir)%array(:, :, :) + &
    2965              :                            v_drhob(ispin)%array(:, :, :)*drhob(idir)%array(:, :, :) + &
    2966              :                            v_drho(ispin)%array(:, :, :)*drho(idir)%array(:, :, :)
    2967              : !$OMP                   END PARALLEL WORKSHARE
    2968              :                      END DO
    2969         5136 :                      IF (ASSOCIATED(e_drhoa)) THEN
    2970              : !$OMP                   PARALLEL WORKSHARE DEFAULT(NONE) &
    2971         5136 : !$OMP                   SHARED(v_drho_r,e_drhoa,drho1a,idir)
    2972              :                         v_drho_r(idir, 1)%array(:, :, :) = v_drho_r(idir, 1)%array(:, :, :) - &
    2973              :                                                            e_drhoa(:, :, :)*drho1a(idir)%array(:, :, :)
    2974              : !$OMP                   END PARALLEL WORKSHARE
    2975              :                      END IF
    2976         5136 :                      IF (nspins /= 1 .AND. ASSOCIATED(e_drhob)) THEN
    2977              : !$OMP                   PARALLEL WORKSHARE DEFAULT(NONE)&
    2978         4194 : !$OMP                   SHARED(v_drho_r,e_drhob,drho1b,idir)
    2979              :                         v_drho_r(idir, 2)%array(:, :, :) = v_drho_r(idir, 2)%array(:, :, :) - &
    2980              :                                                            e_drhob(:, :, :)*drho1b(idir)%array(:, :, :)
    2981              : !$OMP                   END PARALLEL WORKSHARE
    2982              :                      END IF
    2983         6848 :                      IF (ASSOCIATED(e_drho)) THEN
    2984              : !$OMP                   PARALLEL DO PRIVATE(k,j,i) DEFAULT(NONE)&
    2985         5136 : !$OMP                   SHARED(bo,v_drho_r,e_drho,drho1a,drho1b,drho1,fac,idir,nspins) COLLAPSE(3)
    2986              :                         DO k = bo(1, 3), bo(2, 3)
    2987              :                            DO j = bo(1, 2), bo(2, 2)
    2988              :                               DO i = bo(1, 1), bo(2, 1)
    2989              :                                  IF (nspins /= 1) THEN
    2990              :                                     v_drho_r(idir, 1)%array(i, j, k) = v_drho_r(idir, 1)%array(i, j, k) - &
    2991              :                                                                        e_drho(i, j, k)*drho1(idir)%array(i, j, k)
    2992              :                                     v_drho_r(idir, 2)%array(i, j, k) = v_drho_r(idir, 2)%array(i, j, k) - &
    2993              :                                                                        e_drho(i, j, k)*drho1(idir)%array(i, j, k)
    2994              :                                  ELSE
    2995              :                                     v_drho_r(idir, 1)%array(i, j, k) = v_drho_r(idir, 1)%array(i, j, k) - &
    2996              :                                                                        e_drho(i, j, k)*(drho1a(idir)%array(i, j, k) + &
    2997              :                                                                                         fac*drho1b(idir)%array(i, j, k))
    2998              :                                  END IF
    2999              :                               END DO
    3000              :                            END DO
    3001              :                         END DO
    3002              : !$OMP END PARALLEL DO
    3003              :                      END IF
    3004              :                   END DO
    3005              : 
    3006              :                   ! partial integration
    3007         4822 :                   DO ispin = 1, nspins
    3008         4822 :                      CALL xc_pw_divergence(xc_deriv_method_id, v_drho_r(:, ispin), tmp_g, vxc_g, v_xc(ispin))
    3009              :                   END DO ! ispin
    3010              : 
    3011              :                END IF
    3012              : 
    3013              :             END IF ! .NOT.do_spinflip
    3014              : 
    3015        10952 :             DO idir = 1, 3
    3016         8214 :                DEALLOCATE (drho(idir)%array)
    3017        10952 :                DEALLOCATE (drho1(idir)%array)
    3018              :             END DO
    3019              : 
    3020         7452 :             DO ispin = 1, nspins
    3021         4714 :                CALL deallocate_pw(v_drhoa(ispin), pw_pool)
    3022         7452 :                CALL deallocate_pw(v_drhob(ispin), pw_pool)
    3023              :             END DO
    3024              : 
    3025         2738 :             DEALLOCATE (v_drhoa, v_drhob)
    3026              : 
    3027              :          END IF ! gradient_f
    3028              : 
    3029         5168 :          IF (laplace_f .AND. my_compute_virial) THEN
    3030        15026 :             virial_pw%array(:, :, :) = -rhoa(:, :, :)
    3031            2 :             CALL virial_laplace(virial_pw, pw_pool, virial_xc, v_laplace(1)%array)
    3032        15026 :             virial_pw%array(:, :, :) = -rhob(:, :, :)
    3033            2 :             CALL virial_laplace(virial_pw, pw_pool, virial_xc, v_laplace(2)%array)
    3034              :          END IF
    3035              : 
    3036              :       ELSE
    3037              : 
    3038              :          !-----------------!
    3039              :          ! restricted case !
    3040              :          !-----------------!
    3041              : 
    3042        28028 :          CALL xc_rho_set_get(rho1_set, rho=rho1)
    3043              : 
    3044        28028 :          IF (gradient_f) THEN
    3045        18180 :             CALL xc_rho_set_get(rho_set, drho=drho, norm_drho=norm_drho)
    3046        18180 :             CALL xc_rho_set_get(rho1_set, drho=drho1)
    3047        18180 :             CALL prepare_dr1dr(dr1dr, drho, drho1)
    3048              :          END IF
    3049              : 
    3050        28028 :          IF (laplace_f) THEN
    3051          136 :             CALL xc_rho_set_get(rho1_set, laplace_rho=laplace1)
    3052              : 
    3053          544 :             ALLOCATE (v_laplace(nspins))
    3054          272 :             DO ispin = 1, nspins
    3055          272 :                CALL allocate_pw(v_laplace(ispin), pw_pool, bo)
    3056              :             END DO
    3057              : 
    3058          136 :             IF (my_compute_virial) CALL xc_rho_set_get(rho_set, rho=rho)
    3059              :          END IF
    3060              : 
    3061        28028 :          IF (tau_f) THEN
    3062          582 :             CALL xc_rho_set_get(rho1_set, tau=tau1)
    3063              :          END IF
    3064              : 
    3065       322544 :          $:add_2nd_derivative_terms(arguments_closedshell)
    3066              : 
    3067        28028 :          IF (gradient_f) THEN
    3068              : 
    3069        18180 :             IF (my_compute_virial) THEN
    3070          222 :                CALL virial_drho_drho(virial_pw, drho, v_drho(1), virial_xc)
    3071              :             END IF ! my_compute_virial
    3072              : 
    3073        18180 :             IF (my_gapw) THEN
    3074              : 
    3075        29672 :                DO idir = 1, 3
    3076              : !$OMP PARALLEL DO DEFAULT(NONE) &
    3077              : !$OMP             PRIVATE(ia,ir) &
    3078              : !$OMP             SHARED(bo,vxg,drho,v_drho,e_drho,drho1,idir,factor2) &
    3079        29672 : !$OMP             COLLAPSE(2)
    3080              :                   DO ia = bo(1, 1), bo(2, 1)
    3081              :                      DO ir = bo(1, 2), bo(2, 2)
    3082              :                         vxg(idir, ia, ir, 1) = -drho(idir)%array(ia, ir, 1)*v_drho(1)%array(ia, ir, 1)
    3083              :                         IF (ASSOCIATED(e_drho)) THEN
    3084              :                            vxg(idir, ia, ir, 1) = vxg(idir, ia, ir, 1) + factor2*drho1(idir)%array(ia, ir, 1)*e_drho(ia, ir, 1)
    3085              :                         END IF
    3086              :                      END DO
    3087              :                   END DO
    3088              : !$OMP END PARALLEL DO
    3089              :                END DO
    3090              : 
    3091              :             ELSE
    3092              :                ! partial integration
    3093        43048 :                DO idir = 1, 3
    3094        43048 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(v_drho_r,drho,v_drho,drho1,e_drho,idir)
    3095              :                   v_drho_r(idir, 1)%array(:, :, :) = drho(idir)%array(:, :, :)*v_drho(1)%array(:, :, :) - &
    3096              :                                                      drho1(idir)%array(:, :, :)*e_drho(:, :, :)
    3097              : !$OMP END PARALLEL WORKSHARE
    3098              :                END DO
    3099              : 
    3100        10762 :                CALL xc_pw_divergence(xc_deriv_method_id, v_drho_r(:, 1), tmp_g, vxc_g, v_xc(1))
    3101              :             END IF
    3102              : 
    3103              :          END IF
    3104              : 
    3105        28028 :          IF (laplace_f .AND. my_compute_virial) THEN
    3106       294530 :             virial_pw%array(:, :, :) = -rho(:, :, :)
    3107           14 :             CALL virial_laplace(virial_pw, pw_pool, virial_xc, v_laplace(1)%array)
    3108              :          END IF
    3109              : 
    3110              :       END IF
    3111              : 
    3112        33196 :       IF (laplace_f) THEN
    3113          386 :          DO ispin = 1, nspins
    3114          212 :             CALL xc_pw_laplace(v_laplace(ispin), pw_pool, xc_deriv_method_id)
    3115          386 :             CALL pw_axpy(v_laplace(ispin), v_xc(ispin))
    3116              :          END DO
    3117              :       END IF
    3118              : 
    3119        33196 :       IF (gradient_f) THEN
    3120              : 
    3121        43812 :          DO ispin = 1, nspins
    3122        22894 :             CALL deallocate_pw(v_drho(ispin), pw_pool)
    3123       112494 :             DO idir = 1, 3
    3124        91576 :                CALL deallocate_pw(v_drho_r(idir, ispin), pw_pool)
    3125              :             END DO
    3126              :          END DO
    3127        20918 :          DEALLOCATE (v_drho, v_drho_r)
    3128              : 
    3129              :       END IF
    3130              : 
    3131        33196 :       IF (laplace_f) THEN
    3132          386 :       DO ispin = 1, nspins
    3133          386 :          CALL deallocate_pw(v_laplace(ispin), pw_pool)
    3134              :       END DO
    3135          174 :       DEALLOCATE (v_laplace)
    3136              :       END IF
    3137              : 
    3138        33196 :       IF (ASSOCIATED(tmp_g%pw_grid) .AND. ASSOCIATED(pw_pool)) THEN
    3139        12300 :          CALL pw_pool%give_back_pw(tmp_g)
    3140              :       END IF
    3141              : 
    3142        33196 :       IF (ASSOCIATED(vxc_g%pw_grid) .AND. ASSOCIATED(pw_pool)) THEN
    3143        12300 :          CALL pw_pool%give_back_pw(vxc_g)
    3144              :       END IF
    3145              : 
    3146        33196 :       IF (my_compute_virial .AND. (gradient_f .OR. laplace_f)) THEN
    3147          232 :          CALL deallocate_pw(virial_pw, pw_pool)
    3148              :       END IF
    3149              : 
    3150        33196 :       CALL timestop(handle)
    3151              : 
    3152        99588 :    END SUBROUTINE xc_calc_2nd_deriv_analytical
    3153              : 
    3154              : ! **************************************************************************************************
    3155              : !> \brief Calculates the third functional derivative of the exchange-correlation functional, E_xc.
    3156              : !>      Any GGA functional can be written as:
    3157              : !>
    3158              : !>        E_xc[\rho] = \int e_xc(\rho,\nabla\rho)dr
    3159              : !>
    3160              : !>      This routine gives you back the contraction of the derivatives of e_xc with respect to the
    3161              : !>      alpha or beta density or with respect to the norm of their gradients contracted with rho1.
    3162              : !>      For example, the alpha component would be (d stands for total derivative):
    3163              : !>
    3164              : !>                                          d^3 e_xc
    3165              : !>        v_xc(1) = \sum_{s,s'}^{a,b} ---------------------\rhos1\rho1s'
    3166              : !>                                    d\rhoa d\rhos d\rhos'
    3167              : !>
    3168              : !> \param v_xc       Third derivative of the exchange-correlation functional
    3169              : !> \param v_xc_tau ...
    3170              : !> \param deriv_set  derivatives of the exchange-correlation potential, e_xc
    3171              : !> \param rho_set    object containing the density at which the derivatives were calculated, \rho
    3172              : !> \param rho1_set   object containing the density with which to fold, \rho1s
    3173              : !> \param pw_pool    the pool for the grids
    3174              : !> \param xc_section XC parameters
    3175              : !> \par History
    3176              : !>    * 07.2024 Created [LHS]
    3177              : ! **************************************************************************************************
    3178            0 :    SUBROUTINE xc_calc_3rd_deriv_analytical(v_xc, v_xc_tau, deriv_set, rho_set, rho1_set, &
    3179              :                                            pw_pool, xc_section, spinflip)
    3180              : 
    3181              :       TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER        :: v_xc, v_xc_tau
    3182              :       TYPE(xc_derivative_set_type)                       :: deriv_set
    3183              :       TYPE(xc_rho_set_type), INTENT(IN)                  :: rho_set, rho1_set
    3184              :       TYPE(pw_pool_type), POINTER                        :: pw_pool
    3185              :       TYPE(section_vals_type), POINTER                   :: xc_section
    3186              :       LOGICAL, INTENT(in), OPTIONAL                      :: spinflip
    3187              : 
    3188              :       CHARACTER(len=*), PARAMETER :: routineN = 'xc_calc_3rd_deriv_analytical'
    3189              : 
    3190              :       INTEGER                                            :: handle, i, idir, ispin, j, &
    3191              :                                                             k, nspins, xc_deriv_method_id
    3192              :       INTEGER, DIMENSION(2, 3)                           :: bo
    3193              :       LOGICAL                                            :: lsd, do_spinflip, alda0, &
    3194              :                                                             rho_f, gradient_f, tau_f, laplace_f
    3195              :       REAL(KIND=dp)                                      :: s, S_THRESH, S_THRESH2, gradient_cut
    3196            0 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: dr1dr, dra1dra, drb1drb
    3197            0 :       REAL(kind=dp), DIMENSION(:, :, :), POINTER         :: deriv_data, deriv_data2, e_drhoa, e_drhob, &
    3198            0 :                                                             e_drho, norm_drho, norm_drhoa, &
    3199            0 :                                                             norm_drhob, rho1a, rho1b, &
    3200            0 :                                                             rhoa, rhob
    3201            0 :       TYPE(cp_3d_r_cp_type), DIMENSION(3)                :: drho, drho1, drho1a, drho1b, drhoa, drhob
    3202            0 :       TYPE(pw_r3d_rs_type), DIMENSION(:), ALLOCATABLE    :: v_drhoa, v_drhob, v_drho
    3203            0 :       TYPE(pw_r3d_rs_type), DIMENSION(:, :), ALLOCATABLE :: v_drho_r
    3204              :       TYPE(pw_c1d_gs_type)                               :: tmp_g, vxc_g
    3205              :       TYPE(xc_derivative_type), POINTER                  :: deriv_att
    3206              : 
    3207            0 :       CALL timeset(routineN, handle)
    3208              : 
    3209            0 :       NULLIFY (e_drhoa, e_drhob, e_drho)
    3210              : 
    3211            0 :       CPASSERT(ASSOCIATED(v_xc))
    3212            0 :       CPASSERT(ASSOCIATED(xc_section))
    3213              : 
    3214              :       ! Initialize parameters
    3215              :       CALL section_vals_val_get(xc_section, "XC_GRID%XC_DERIV", &
    3216            0 :                                 i_val=xc_deriv_method_id)
    3217              :       !
    3218            0 :       nspins = SIZE(v_xc)
    3219            0 :       lsd = ASSOCIATED(rho_set%rhoa)
    3220              :       !
    3221            0 :       do_spinflip = .FALSE.
    3222            0 :       IF (PRESENT(spinflip)) do_spinflip = spinflip
    3223              :       !
    3224            0 :       bo = rho_set%local_bounds
    3225              :       !
    3226            0 :       CALL check_for_derivatives(deriv_set, lsd, rho_f, gradient_f, tau_f, laplace_f)
    3227              :       !
    3228            0 :       CALL xc_rho_set_get(rho_set, drho_cutoff=gradient_cut)
    3229              :       !
    3230              :       !S_THRESH has to be the same as S_THRESH in xc_calc_2nd_deriv_analytical
    3231            0 :       alda0 = .false.
    3232            0 :       S_THRESH = 1.0E-04
    3233            0 :       S_THRESH2 = 1.0E-07
    3234              : 
    3235              :       ! Initialize potential
    3236            0 :       DO ispin = 1, nspins
    3237              :          !CALL pw_zero(v_xc(ispin))
    3238            0 :          v_xc(ispin)%array = 0.0_dp
    3239              :       END DO
    3240              : 
    3241              :       ! Create GGA fields
    3242            0 :       IF (gradient_f) THEN
    3243            0 :          ALLOCATE (v_drho_r(3, nspins), v_drho(nspins))
    3244            0 :          DO ispin = 1, nspins
    3245            0 :             DO idir = 1, 3
    3246            0 :                CALL allocate_pw(v_drho_r(idir, ispin), pw_pool, bo)
    3247              :             END DO
    3248            0 :             CALL allocate_pw(v_drho(ispin), pw_pool, bo)
    3249              :          END DO
    3250              : 
    3251            0 :          IF (xc_requires_tmp_g(xc_deriv_method_id)) THEN
    3252            0 :             IF (ASSOCIATED(pw_pool)) THEN
    3253            0 :                CALL pw_pool%create_pw(tmp_g)
    3254            0 :                CALL pw_pool%create_pw(vxc_g)
    3255              :             ELSE
    3256              :                ! remember to refix for gapw
    3257            0 :                CPABORT("XC_DERIV method is not implemented in GAPW")
    3258              :             END IF
    3259              :          END IF
    3260              : 
    3261              :       END IF
    3262              : 
    3263              :       ! Initialize mGGA potential
    3264            0 :       IF (tau_f) THEN
    3265            0 :          CPASSERT(ASSOCIATED(v_xc_tau))
    3266            0 :          DO ispin = 1, nspins
    3267            0 :             v_xc_tau(ispin)%array = 0.0_dp
    3268              :          END DO
    3269              :       END IF
    3270              : 
    3271            0 :       IF (lsd) THEN
    3272              : 
    3273              :          !-------------------!
    3274              :          ! UNrestricted case !
    3275              :          !-------------------!
    3276              : 
    3277            0 :          IF (do_spinflip) THEN
    3278            0 :             CALL xc_rho_set_get(rho1_set, rhoa=rho1a)
    3279            0 :             CALL xc_rho_set_get(rho_set, rhoa=rhoa, rhob=rhob)
    3280              :          ELSE
    3281            0 :             CALL xc_rho_set_get(rho1_set, rhoa=rho1a, rhob=rho1b)
    3282              :          END IF
    3283              : 
    3284            0 :          IF (gradient_f) THEN
    3285              :             CALL xc_rho_set_get(rho_set, drhoa=drhoa, drhob=drhob, &
    3286            0 :                                 norm_drho=norm_drho, norm_drhoa=norm_drhoa, norm_drhob=norm_drhob)
    3287            0 :             IF (do_spinflip) THEN
    3288            0 :                CALL xc_rho_set_get(rho1_set, drhoa=drho1a)
    3289            0 :                CALL calc_drho_from_a(drho1, drho1a)
    3290              :             ELSE
    3291            0 :                CALL xc_rho_set_get(rho1_set, drhoa=drho1a, drhob=drho1b)
    3292            0 :                CALL calc_drho_from_ab(drho1, drho1a, drho1b)
    3293              :             END IF
    3294              : 
    3295            0 :             CALL calc_drho_from_ab(drho, drhoa, drhob)
    3296              : 
    3297            0 :             CALL prepare_dr1dr(dra1dra, drhoa, drho1a)
    3298            0 :             IF (do_spinflip) THEN
    3299            0 :                CALL prepare_dr1dr(drb1drb, drhob, drho1a)
    3300            0 :                CALL prepare_dr1dr(dr1dr, drho, drho1a)
    3301            0 :             ELSE IF (nspins /= 1) THEN
    3302            0 :                CALL prepare_dr1dr(drb1drb, drhob, drho1b)
    3303            0 :                CALL prepare_dr1dr(dr1dr, drho, drho1)
    3304              :             ELSE
    3305            0 :                CPABORT("Exchange-correlation's third derivative for closed-shell not yet implemented")
    3306              :             END IF
    3307              : 
    3308              :             ! Create vectors for partial integration term
    3309            0 :             ALLOCATE (v_drhoa(nspins), v_drhob(nspins))
    3310            0 :             DO ispin = 1, nspins
    3311            0 :                CALL allocate_pw(v_drhoa(ispin), pw_pool, bo)
    3312            0 :                CALL allocate_pw(v_drhob(ispin), pw_pool, bo)
    3313              :             END DO
    3314              : 
    3315              :          END IF
    3316              : 
    3317            0 :          IF (laplace_f) THEN
    3318            0 :             CPABORT("Exchange-correlation's laplace analytic third derivative not implemented")
    3319              :          END IF
    3320              : 
    3321            0 :          IF (tau_f) THEN
    3322            0 :             CPABORT("Exchange-correlation's mGGA analytic third derivative not implemented")
    3323              :          END IF
    3324              : 
    3325            0 :          IF (nspins /= 1) THEN
    3326              : 
    3327            0 :             IF (.NOT. do_spinflip) THEN
    3328              :                ! Analytic third derivative of the excchange-correlation functional
    3329            0 :                CPABORT("Exchange-correlation's analytic third derivative not implemented")
    3330              : 
    3331              :             ELSE
    3332              : 
    3333              :                ! vxc contributions
    3334              :                !   vxca = (vxc^{\alpha}-vxc^{\beta})*rho1/|rhoa-rhob|^2
    3335              :                !   vxcb =-(vxc^{\alpha}-vxc^{\beta})*rho1/|rhoa-rhob|^2
    3336              :                !     Alpha LDA contribution
    3337              :                !                 | d e_xc     d e_xc |      rho1a
    3338              :                !   vxca =  rho1a*|-------- - --------|*---------------
    3339              :                !                 | drhoa      drhob  | |rhoa - rhob|^2
    3340            0 :                deriv_att => xc_dset_get_derivative(deriv_set, [deriv_rhoa])
    3341            0 :                IF (ASSOCIATED(deriv_att)) THEN
    3342            0 :                   CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
    3343            0 :                   deriv_att => xc_dset_get_derivative(deriv_set, [deriv_rhob])
    3344            0 :                   IF (ASSOCIATED(deriv_att)) THEN
    3345            0 :                      CALL xc_derivative_get(deriv_att, deriv_data=deriv_data2)
    3346              : !$OMP                PARALLEL DO PRIVATE(k,j,i,s) DEFAULT(NONE)&
    3347            0 : !$OMP                SHARED(bo,v_xc,deriv_data,deriv_data2,rho1a,rhoa,rhob,S_THRESH2) COLLAPSE(3)
    3348              :                      DO k = bo(1, 3), bo(2, 3)
    3349              :                         DO j = bo(1, 2), bo(2, 2)
    3350              :                            DO i = bo(1, 1), bo(2, 1)
    3351              :                               s = rhoa(i, j, k) - rhob(i, j, k)
    3352              :                               s = -SIGN(MAX(s**2, S_THRESH2), s)
    3353              :                               v_xc(1)%array(i, j, k) = v_xc(1)%array(i, j, k) + &
    3354              :                                                        (deriv_data(i, j, k) - deriv_data2(i, j, k))*rho1a(i, j, k)**2/s
    3355              :                            END DO
    3356              :                         END DO
    3357              :                      END DO
    3358              : !$OMP                END PARALLEL DO
    3359              :                   END IF
    3360              :                END IF
    3361              :                ! GGA contributions to the spin-flip xcKernel
    3362              :                !     Alpha GGA contributions
    3363              :                !             |  d e_xc              d e_xc           |      rho1a
    3364              :                !   vxca += + |----------*dra1dra - ----------*drb1drb|*---------------
    3365              :                !             | d|drhoa|             d|drhob|         | |rhoa - rhob|^2
    3366              :                IF (.NOT. alda0) THEN
    3367            0 :                   deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drhoa])
    3368            0 :                   IF (ASSOCIATED(deriv_att)) THEN
    3369            0 :                      CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
    3370            0 :                      deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drhob])
    3371            0 :                      IF (ASSOCIATED(deriv_att)) THEN
    3372            0 :                         CALL xc_derivative_get(deriv_att, deriv_data=deriv_data2)
    3373              : !$OMP                PARALLEL DO PRIVATE(k,j,i,s) DEFAULT(NONE)&
    3374            0 : !$OMP                SHARED(bo,deriv_data,deriv_data2,dra1dra,drb1drb,v_xc,rho1a,rhoa,rhob,S_THRESH2) COLLAPSE(3)
    3375              :                         DO k = bo(1, 3), bo(2, 3)
    3376              :                            DO j = bo(1, 2), bo(2, 2)
    3377              :                               DO i = bo(1, 1), bo(2, 1)
    3378              :                                  s = rhoa(i, j, k) - rhob(i, j, k)
    3379              :                                  s = -SIGN(MAX(s**2, S_THRESH2), s)
    3380              :                                  v_xc(1)%array(i, j, k) = v_xc(1)%array(i, j, k) + &
    3381              :                                                     (deriv_data(i, j, k)*dra1dra(i, j, k) - deriv_data2(i, j, k)*drb1drb(i, j, k)) &
    3382              :                                                           *rho1a(i, j, k)/s
    3383              :                               END DO
    3384              :                            END DO
    3385              :                         END DO
    3386              : !$OMP                END PARALLEL DO
    3387              :                      END IF
    3388              :                   END IF
    3389              :                END IF
    3390              :                !     Beta contribution = - alpha
    3391              : !$OMP          PARALLEL DO PRIVATE(k,j,i,s) DEFAULT(NONE)&
    3392            0 : !$OMP          SHARED(bo,v_xc) COLLAPSE(3)
    3393              :                DO k = bo(1, 3), bo(2, 3)
    3394              :                   DO j = bo(1, 2), bo(2, 2)
    3395              :                      DO i = bo(1, 1), bo(2, 1)
    3396              :                         v_xc(2)%array(i, j, k) = -v_xc(1)%array(i, j, k)
    3397              :                      END DO
    3398              :                   END DO
    3399              :                END DO
    3400              : !$OMP          END PARALLEL DO
    3401              :                ! fxc contributions
    3402              :                !   vxca = rho1*(fxc^{\alpha\alpha}-fxc^{\alpha\beta})*rho1/|rhoa-rhob|
    3403              :                !   vxcb = rho1*(fxc^{\beta\alpha}-fxc^{\beta\beta})*rho1/|rhoa-rhob|
    3404              :                !     Alpha LDA contribution
    3405              :                !                  |  d^2 e_xc        d^2 e_xc   |     rho1a
    3406              :                !   vxca +=  rho1a*|------------- - -------------|*-------------
    3407              :                !                  | drhoa drhoa     drhoa drhob | |rhoa - rhob|
    3408            0 :                deriv_att => xc_dset_get_derivative(deriv_set, [deriv_rhoa, deriv_rhob])
    3409            0 :                IF (ASSOCIATED(deriv_att)) THEN
    3410            0 :                   CALL xc_derivative_get(deriv_att, deriv_data=deriv_data2)
    3411            0 :                   deriv_att => xc_dset_get_derivative(deriv_set, [deriv_rhoa, deriv_rhoa])
    3412            0 :                   IF (ASSOCIATED(deriv_att)) THEN
    3413            0 :                      CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
    3414              : !$OMP                PARALLEL DO PRIVATE(k,j,i,s) DEFAULT(NONE)&
    3415            0 : !$OMP                SHARED(bo,deriv_data,deriv_data2,rho1a,v_xc,rhoa,rhob,S_THRESH) COLLAPSE(3)
    3416              :                      DO k = bo(1, 3), bo(2, 3)
    3417              :                         DO j = bo(1, 2), bo(2, 2)
    3418              :                            DO i = bo(1, 1), bo(2, 1)
    3419              :                               s = MAX(ABS(rhoa(i, j, k) - rhob(i, j, k)), S_THRESH)
    3420              :                               v_xc(1)%array(i, j, k) = v_xc(1)%array(i, j, k) + &
    3421              :                                                        rho1a(i, j, k)**2*(deriv_data(i, j, k) - deriv_data2(i, j, k))/s
    3422              :                            END DO
    3423              :                         END DO
    3424              :                      END DO
    3425              : !$OMP                END PARALLEL DO
    3426              :                   END IF
    3427              :                END IF
    3428              :                !     Beta LDA contribution
    3429              :                !                  |  d^2 e_xc        d^2 e_xc   |    rho1a
    3430              :                !   vxcb +=  rho1a*|------------- - -------------|*-------------
    3431              :                !                  | drhob drhoa     drhob drhob | |rhoa - rhob|
    3432            0 :                deriv_att => xc_dset_get_derivative(deriv_set, [deriv_rhob, deriv_rhob])
    3433            0 :                IF (ASSOCIATED(deriv_att)) THEN
    3434            0 :                   CALL xc_derivative_get(deriv_att, deriv_data=deriv_data2)
    3435            0 :                   deriv_att => xc_dset_get_derivative(deriv_set, [deriv_rhob, deriv_rhoa])
    3436            0 :                   IF (ASSOCIATED(deriv_att)) THEN
    3437            0 :                      CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
    3438              : !$OMP                PARALLEL DO PRIVATE(k,j,i,s) DEFAULT(NONE)&
    3439            0 : !$OMP                SHARED(bo,deriv_data,deriv_data2,rho1a,v_xc,rhoa,rhob,S_THRESH) COLLAPSE(3)
    3440              :                      DO k = bo(1, 3), bo(2, 3)
    3441              :                         DO j = bo(1, 2), bo(2, 2)
    3442              :                            DO i = bo(1, 1), bo(2, 1)
    3443              :                               s = MAX(ABS(rhoa(i, j, k) - rhob(i, j, k)), S_THRESH)
    3444              :                               v_xc(2)%array(i, j, k) = v_xc(2)%array(i, j, k) + &
    3445              :                                                        rho1a(i, j, k)**2*(deriv_data(i, j, k) - deriv_data2(i, j, k))/s
    3446              :                            END DO
    3447              :                         END DO
    3448              :                      END DO
    3449              : !$OMP                END PARALLEL DO
    3450              :                   END IF
    3451              :                END IF
    3452              :                !     Alpha GGA contribution
    3453              :                IF (.NOT. alda0) THEN
    3454              :                   !                 rho1a     |    d^2 e_xc                   d^2 e_xc            |
    3455              :                   !   vxca += + -------------*|----------------*dra1dra - ----------------*drb1drb|
    3456              :                   !             |rhoa - rhob| | drhoa d|drhoa|             drhoa d|drhob|         |
    3457            0 :                   deriv_att => xc_dset_get_derivative(deriv_set, [deriv_rhoa, deriv_norm_drhob])
    3458            0 :                   IF (ASSOCIATED(deriv_att)) THEN
    3459            0 :                      CALL xc_derivative_get(deriv_att, deriv_data=deriv_data2)
    3460            0 :                      deriv_att => xc_dset_get_derivative(deriv_set, [deriv_rhoa, deriv_norm_drhoa])
    3461            0 :                      IF (ASSOCIATED(deriv_att)) THEN
    3462            0 :                         CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
    3463              : !$OMP                PARALLEL DO PRIVATE(k,j,i,s) DEFAULT(NONE)&
    3464            0 : !$OMP                SHARED(bo,deriv_data,deriv_data2,dra1dra,drb1drb,rho1a,v_xc,rhoa,rhob,S_THRESH) COLLAPSE(3)
    3465              :                         DO k = bo(1, 3), bo(2, 3)
    3466              :                            DO j = bo(1, 2), bo(2, 2)
    3467              :                               DO i = bo(1, 1), bo(2, 1)
    3468              :                                  s = MAX(ABS(rhoa(i, j, k) - rhob(i, j, k)), S_THRESH)
    3469              :                                  v_xc(1)%array(i, j, k) = v_xc(1)%array(i, j, k) + &
    3470              :                                                    (deriv_data(i, j, k)*dra1dra(i, j, k) - deriv_data2(i, j, k)*drb1drb(i, j, k))* &
    3471              :                                                           rho1a(i, j, k)/s
    3472              :                               END DO
    3473              :                            END DO
    3474              :                         END DO
    3475              : !$OMP                END PARALLEL DO
    3476              :                      END IF
    3477              :                   END IF
    3478              :                   !     Beta GGA contribution
    3479              :                   !                 rho1a     |    d^2 e_xc                   d^2 e_xc            |
    3480              :                   !   vxcb += + -------------*|----------------*dra1dra - ----------------*drb1drb|
    3481              :                   !             |rhoa - rhob| | drhob d|drhoa|             drhob d|drhob|         |
    3482            0 :                   deriv_att => xc_dset_get_derivative(deriv_set, [deriv_rhob, deriv_norm_drhob])
    3483            0 :                   IF (ASSOCIATED(deriv_att)) THEN
    3484            0 :                      CALL xc_derivative_get(deriv_att, deriv_data=deriv_data2)
    3485            0 :                      deriv_att => xc_dset_get_derivative(deriv_set, [deriv_rhob, deriv_norm_drhoa])
    3486            0 :                      IF (ASSOCIATED(deriv_att)) THEN
    3487            0 :                         CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
    3488              : !$OMP                PARALLEL DO PRIVATE(k,j,i,s) DEFAULT(NONE)&
    3489            0 : !$OMP                SHARED(bo,deriv_data,deriv_data2,dra1dra,drb1drb,rho1a,v_xc,rhoa,rhob,S_THRESH) COLLAPSE(3)
    3490              :                         DO k = bo(1, 3), bo(2, 3)
    3491              :                            DO j = bo(1, 2), bo(2, 2)
    3492              :                               DO i = bo(1, 1), bo(2, 1)
    3493              :                                  s = MAX(ABS(rhoa(i, j, k) - rhob(i, j, k)), S_THRESH)
    3494              :                                  v_xc(2)%array(i, j, k) = v_xc(2)%array(i, j, k) + &
    3495              :                                                    (deriv_data(i, j, k)*dra1dra(i, j, k) - deriv_data2(i, j, k)*drb1drb(i, j, k))* &
    3496              :                                                           rho1a(i, j, k)/s
    3497              :                               END DO
    3498              :                            END DO
    3499              :                         END DO
    3500              : !$OMP                END PARALLEL DO
    3501              :                      END IF
    3502              :                   END IF
    3503              :                   !
    3504              :                   !
    3505              :                   ! Calculate the vector for the partial integration term of GGA functionals
    3506              :                   !   First contribution alpha
    3507              :                   !                  |    d^2 e_xc           d^2 e_xc    |
    3508              :                   !   v_drhoa(1) += -|---------------- - ----------------|*rho1a
    3509              :                   !                  | d|drhoa| drhoa     d|drhoa| drhob |
    3510            0 :                   deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drhoa, deriv_rhob])
    3511            0 :                   IF (ASSOCIATED(deriv_att)) THEN
    3512            0 :                      CALL xc_derivative_get(deriv_att, deriv_data=deriv_data2)
    3513            0 :                      deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drhoa, deriv_rhoa])
    3514            0 :                      IF (ASSOCIATED(deriv_att)) THEN
    3515            0 :                         CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
    3516              : !$OMP                PARALLEL DO PRIVATE(k,j,i) DEFAULT(NONE)&
    3517            0 : !$OMP                SHARED(bo,deriv_data,deriv_data2,rho1a,v_drhoa) COLLAPSE(3)
    3518              :                         DO k = bo(1, 3), bo(2, 3)
    3519              :                            DO j = bo(1, 2), bo(2, 2)
    3520              :                               DO i = bo(1, 1), bo(2, 1)
    3521              :                                  v_drhoa(1)%array(i, j, k) = v_drhoa(1)%array(i, j, k) - &
    3522              :                                                              (deriv_data(i, j, k) - deriv_data2(i, j, k))*rho1a(i, j, k)
    3523              :                               END DO
    3524              :                            END DO
    3525              :                         END DO
    3526              : !$OMP                END PARALLEL DO
    3527              :                      END IF
    3528              :                   END IF
    3529              :                   !   First contribution beta
    3530              :                   !                  |    d^2 e_xc           d^2 e_xc    |
    3531              :                   !   v_drhob(2) += +|---------------- - ----------------|*rho1a
    3532              :                   !                  | d|drhob| drhob     d|drhob| drhoa |
    3533            0 :                   deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drhob, deriv_rhoa])
    3534            0 :                   IF (ASSOCIATED(deriv_att)) THEN
    3535            0 :                      CALL xc_derivative_get(deriv_att, deriv_data=deriv_data2)
    3536            0 :                      deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drhob, deriv_rhob])
    3537            0 :                      IF (ASSOCIATED(deriv_att)) THEN
    3538            0 :                         CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
    3539              : !$OMP                PARALLEL DO PRIVATE(k,j,i) DEFAULT(NONE)&
    3540            0 : !$OMP                SHARED(bo,deriv_data,deriv_data2,rho1a,v_drhob) COLLAPSE(3)
    3541              :                         DO k = bo(1, 3), bo(2, 3)
    3542              :                            DO j = bo(1, 2), bo(2, 2)
    3543              :                               DO i = bo(1, 1), bo(2, 1)
    3544              :                                  v_drhob(2)%array(i, j, k) = v_drhob(2)%array(i, j, k) + &
    3545              :                                                              (deriv_data(i, j, k) - deriv_data2(i, j, k))*rho1a(i, j, k)
    3546              :                               END DO
    3547              :                            END DO
    3548              :                         END DO
    3549              : !$OMP                END PARALLEL DO
    3550              :                      END IF
    3551              :                   END IF
    3552              :                   !   First contribution spinless
    3553              :                   !                 |   d^2 e_xc          d^2 e_xc    |
    3554              :                   !   v_drho(1) += -|--------------- - ---------------|*rho1a
    3555              :                   !                 | d|drho| drhoa     d|drho| drhob |
    3556              :                   !
    3557              :                   !                 |   d^2 e_xc          d^2 e_xc    |
    3558              :                   !   v_drho(2) += -|--------------- - ---------------|*rho1a
    3559              :                   !                 | d|drho| drhoa     d|drho| drhob |
    3560            0 :                   deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drho, deriv_rhoa])
    3561            0 :                   IF (ASSOCIATED(deriv_att)) THEN
    3562            0 :                      CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
    3563            0 :                      deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drho, deriv_rhob])
    3564            0 :                      IF (ASSOCIATED(deriv_att)) THEN
    3565            0 :                         CALL xc_derivative_get(deriv_att, deriv_data=deriv_data2)
    3566              : !$OMP                PARALLEL DO PRIVATE(k,j,i) DEFAULT(NONE)&
    3567            0 : !$OMP                SHARED(bo,deriv_data,deriv_data2,rho1a,v_drho) COLLAPSE(3)
    3568              :                         DO k = bo(1, 3), bo(2, 3)
    3569              :                            DO j = bo(1, 2), bo(2, 2)
    3570              :                               DO i = bo(1, 1), bo(2, 1)
    3571              :                                  v_drho(1)%array(i, j, k) = v_drho(1)%array(i, j, k) - &
    3572              :                                                             (deriv_data(i, j, k) - deriv_data2(i, j, k))*rho1a(i, j, k)
    3573              :                                  v_drho(2)%array(i, j, k) = v_drho(2)%array(i, j, k) - &
    3574              :                                                             (deriv_data(i, j, k) - deriv_data2(i, j, k))*rho1a(i, j, k)
    3575              :                               END DO
    3576              :                            END DO
    3577              :                         END DO
    3578              : !$OMP                END PARALLEL DO
    3579              :                      END IF
    3580              :                   END IF
    3581              :                   !   Second contribution
    3582            0 :                   deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drhoa, deriv_norm_drhob])
    3583            0 :                   IF (ASSOCIATED(deriv_att)) THEN
    3584            0 :                      CALL xc_derivative_get(deriv_att, deriv_data=deriv_data2)
    3585              :                      !                        d^2 e_xc                      d^2 e_xc
    3586              :                      !   v_drhoa(1) += - -------------------*dra1dra + ------------------*drb1drb
    3587              :                      !                    d|drhoa| d|drhoa|             d|drhoa| d|drhob|
    3588            0 :                      deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drhoa, deriv_norm_drhoa])
    3589            0 :                      IF (ASSOCIATED(deriv_att)) THEN
    3590            0 :                         CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
    3591              : !$OMP                PARALLEL DO PRIVATE(k,j,i) DEFAULT(NONE)&
    3592            0 : !$OMP                SHARED(bo,deriv_data,deriv_data2,dra1dra,drb1drb,v_drhoa) COLLAPSE(3)
    3593              :                         DO k = bo(1, 3), bo(2, 3)
    3594              :                            DO j = bo(1, 2), bo(2, 2)
    3595              :                               DO i = bo(1, 1), bo(2, 1)
    3596              :                                  v_drhoa(1)%array(i, j, k) = v_drhoa(1)%array(i, j, k) - &
    3597              :                                                         deriv_data(i, j, k)*dra1dra(i, j, k) + deriv_data2(i, j, k)*drb1drb(i, j, k)
    3598              :                               END DO
    3599              :                            END DO
    3600              :                         END DO
    3601              : !$OMP                END PARALLEL DO
    3602              :                      END IF
    3603              :                      !                        d^2 e_xc                      d^2 e_xc
    3604              :                      !   v_drhob(2) += - -------------------*dra1dra + -------------------*drb1drb
    3605              :                      !                    d|drhoa| d|drhob|             d|drhob| d|drhob|
    3606            0 :                      deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drhob, deriv_norm_drhob])
    3607            0 :                      IF (ASSOCIATED(deriv_att)) THEN
    3608            0 :                         CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
    3609              : !$OMP                PARALLEL DO PRIVATE(k,j,i) DEFAULT(NONE)&
    3610            0 : !$OMP                SHARED(bo,deriv_data,deriv_data2,dra1dra,drb1drb,v_drhob) COLLAPSE(3)
    3611              :                         DO k = bo(1, 3), bo(2, 3)
    3612              :                            DO j = bo(1, 2), bo(2, 2)
    3613              :                               DO i = bo(1, 1), bo(2, 1)
    3614              :                                  v_drhob(2)%array(i, j, k) = v_drhob(2)%array(i, j, k) - &
    3615              :                                                         deriv_data(i, j, k)*dra1dra(i, j, k) + deriv_data2(i, j, k)*drb1drb(i, j, k)
    3616              :                               END DO
    3617              :                            END DO
    3618              :                         END DO
    3619              : !$OMP                END PARALLEL DO
    3620              :                      END IF
    3621              :                   END IF
    3622              :                   !                      d^2 e_xc                     d^2 e_xc
    3623              :                   !   v_drho(1) += - ------------------*dra1dra + ------------------*drb1drb
    3624              :                   !                   d|drho| d|drhoa|             d|drho| d|drhob|
    3625              :                   !
    3626              :                   !                      d^2 e_xc                     d^2 e_xc
    3627              :                   !   v_drho(2) += - ------------------*dra1dra + ------------------*drb1drb
    3628              :                   !                   d|drho| d|drhoa|             d|drho| d|drhob|
    3629            0 :                   deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drho, deriv_norm_drhob])
    3630            0 :                   IF (ASSOCIATED(deriv_att)) THEN
    3631            0 :                      CALL xc_derivative_get(deriv_att, deriv_data=deriv_data2)
    3632            0 :                      deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drho, deriv_norm_drhoa])
    3633            0 :                      IF (ASSOCIATED(deriv_att)) THEN
    3634            0 :                         CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
    3635              : !$OMP                PARALLEL DO PRIVATE(k,j,i) DEFAULT(NONE)&
    3636            0 : !$OMP                SHARED(bo,deriv_data,deriv_data2,dra1dra,drb1drb,v_drho) COLLAPSE(3)
    3637              :                         DO k = bo(1, 3), bo(2, 3)
    3638              :                            DO j = bo(1, 2), bo(2, 2)
    3639              :                               DO i = bo(1, 1), bo(2, 1)
    3640              :                                  v_drho(1)%array(i, j, k) = v_drho(1)%array(i, j, k) - &
    3641              :                                                             deriv_data(i, j, k)*dra1dra(i, j, k) + &
    3642              :                                                             deriv_data2(i, j, k)*drb1drb(i, j, k)
    3643              :                                  v_drho(2)%array(i, j, k) = v_drho(2)%array(i, j, k) - &
    3644              :                                                             deriv_data(i, j, k)*dra1dra(i, j, k) + &
    3645              :                                                             deriv_data2(i, j, k)*drb1drb(i, j, k)
    3646              :                               END DO
    3647              :                            END DO
    3648              :                         END DO
    3649              : !$OMP                END PARALLEL DO
    3650              :                      END IF
    3651              :                   END IF
    3652              :                   !
    3653              : 
    3654              :                   ! Last GGA contribution
    3655              :                   !   Alpha contribution
    3656              :                   !                     d e_xc
    3657              :                   !   v_drhoa(1) += + ----------*dra1dra
    3658              :                   !                    d|drhoa|
    3659            0 :                   deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drhoa])
    3660            0 :                   IF (ASSOCIATED(deriv_att)) THEN
    3661            0 :                      CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
    3662            0 :                      CALL xc_derivative_get(deriv_att, deriv_data=e_drhoa)
    3663              : 
    3664            0 : !$OMP             PARALLEL WORKSHARE DEFAULT(NONE) SHARED(dra1dra,gradient_cut,norm_drhoa,v_drhoa,deriv_data)
    3665              :                      v_drhoa(1)%array(:, :, :) = v_drhoa(1)%array(:, :, :) + &
    3666              :                                                  deriv_data(:, :, :)*dra1dra(:, :, :)/MAX(gradient_cut, norm_drhoa(:, :, :))**2
    3667              : !$OMP             END PARALLEL WORKSHARE
    3668              :                   END IF
    3669              :                   !   Beta contribution
    3670              :                   !                     d e_xc
    3671              :                   !   v_drhob(2) += - ----------*drb1drb
    3672              :                   !                    d|drhob|
    3673            0 :                   deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drhob])
    3674            0 :                   IF (ASSOCIATED(deriv_att)) THEN
    3675            0 :                      CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
    3676            0 :                      CALL xc_derivative_get(deriv_att, deriv_data=e_drhob)
    3677              : 
    3678            0 : !$OMP             PARALLEL WORKSHARE DEFAULT(NONE) SHARED(drb1drb,gradient_cut,norm_drhob,v_drhob,deriv_data)
    3679              :                      v_drhob(2)%array(:, :, :) = v_drhob(2)%array(:, :, :) - &
    3680              :                                                  deriv_data(:, :, :)*drb1drb(:, :, :)/MAX(gradient_cut, norm_drhob(:, :, :))**2
    3681              : !$OMP             END PARALLEL WORKSHARE
    3682              :                   END IF
    3683              :                END IF ! If ALDA0
    3684              :             END IF
    3685              : 
    3686              :          ELSE
    3687              : 
    3688              :             ! Analytic third derivative for closed-shell
    3689            0 :             CPABORT("Exchange-correlation's analytic third derivative not implemented")
    3690              : 
    3691              :          END IF
    3692              : 
    3693            0 :          IF (gradient_f) THEN
    3694              :             IF (.NOT. alda0) THEN
    3695              : 
    3696              :                ! partial integration
    3697            0 :                DO idir = 1, 3
    3698              : 
    3699              :                   ! GGA contributions to the spin-flip xc-Kernel
    3700              :                   !
    3701              :                   !                     v_drhoa(1)*drhoa(:)*rhoa1     v_drhob(1)*drhob(:)*rhoa1     v_drho(1)*drho(:)*rhoa1
    3702              :                   !   v_drho_r(:,1) =  --------------------------- + --------------------------- + -------------------------
    3703              :                   !                          |rhoa - rhob|                 |rhoa - rhob|                |rhoa - rhob|
    3704              :                   !
    3705              :                   !                     v_drhoa(2)*drhoa(:)*rhoa1     v_drhob(2)*drhob(:)*rhoa1     v_drho(2)*drho(:)*rhoa1
    3706              :                   !   v_drho_r(:,2) =  --------------------------- + --------------------------- + -------------------------
    3707              :                   !                          |rhoa - rhob|                 |rhoa - rhob|                |rhoa - rhob|
    3708            0 :                   IF (do_spinflip) THEN
    3709              : !$OMP             PARALLEL DO PRIVATE(k,j,i,s) DEFAULT(NONE)&
    3710            0 : !$OMP             SHARED(bo,v_drho_r,v_drho,v_drhoa,v_drhob,rhoa,rhob,drho,drhoa,drhob,rho1a,idir,S_THRESH) COLLAPSE(3)
    3711              :                      DO k = bo(1, 3), bo(2, 3)
    3712              :                         DO j = bo(1, 2), bo(2, 2)
    3713              :                            DO i = bo(1, 1), bo(2, 1)
    3714              :                               s = MAX(ABS(rhoa(i, j, k) - rhob(i, j, k)), S_THRESH)
    3715              :                               DO ispin = 1, 2
    3716              :                                  v_drho_r(idir, ispin)%array(i, j, k) = v_drho_r(idir, ispin)%array(i, j, k) + &
    3717              :                                                        v_drhoa(ispin)%array(i, j, k)*drhoa(idir)%array(i, j, k)*rho1a(i, j, k)/s + &
    3718              :                                                        v_drhob(ispin)%array(i, j, k)*drhob(idir)%array(i, j, k)*rho1a(i, j, k)/s + &
    3719              :                                                              v_drho(ispin)%array(i, j, k)*drho(idir)%array(i, j, k)*rho1a(i, j, k)/s
    3720              :                               END DO
    3721              :                            END DO
    3722              :                         END DO
    3723              :                      END DO
    3724              : !$OMP             END PARALLEL DO
    3725              :                   END IF
    3726              :                   ! Last GGA contribution
    3727              :                   !   Alpha contribution
    3728              :                   !                          rho1a       d e_xc
    3729              :                   !   v_drho_r(:,1) += - -------------*----------*drho1a(:)
    3730              :                   !                      |rhoa - rhob|  d|drhoa|
    3731            0 :                   IF (ASSOCIATED(e_drhoa)) THEN
    3732              : !$OMP             PARALLEL DO PRIVATE(k,j,i,s) DEFAULT(NONE)&
    3733            0 : !$OMP             SHARED(bo,e_drhoa,v_drho_r,drho1a,rho1a,rhoa,rhob,S_THRESH,idir) COLLAPSE(3)
    3734              :                      DO k = bo(1, 3), bo(2, 3)
    3735              :                         DO j = bo(1, 2), bo(2, 2)
    3736              :                            DO i = bo(1, 1), bo(2, 1)
    3737              :                               s = MAX(ABS(rhoa(i, j, k) - rhob(i, j, k)), S_THRESH)
    3738              :                               v_drho_r(idir, 1)%array(i, j, k) = v_drho_r(idir, 1)%array(i, j, k) - &
    3739              :                                                                  e_drhoa(i, j, k)*drho1a(idir)%array(i, j, k)*rho1a(i, j, k)/s
    3740              :                            END DO
    3741              :                         END DO
    3742              :                      END DO
    3743              : !$OMP             END PARALLEL DO
    3744              :                   END IF
    3745              :                   !   Beta contribution
    3746              :                   !                          rho1a       d e_xc
    3747              :                   !   v_drho_r(:,2) += + -------------*----------*drho1a(:)
    3748              :                   !                      |rhoa - rhob|  d|drhob|
    3749            0 :                   IF (ASSOCIATED(e_drhob)) THEN
    3750              : !$OMP             PARALLEL DO PRIVATE(k,j,i,s) DEFAULT(NONE)&
    3751            0 : !$OMP             SHARED(bo,e_drhob,v_drho_r,drho1a,rho1a,rhoa,rhob,S_THRESH,idir) COLLAPSE(3)
    3752              :                      DO k = bo(1, 3), bo(2, 3)
    3753              :                         DO j = bo(1, 2), bo(2, 2)
    3754              :                            DO i = bo(1, 1), bo(2, 1)
    3755              :                               s = MAX(ABS(rhoa(i, j, k) - rhob(i, j, k)), S_THRESH)
    3756              :                               v_drho_r(idir, 2)%array(i, j, k) = v_drho_r(idir, 2)%array(i, j, k) + &
    3757              :                                                                  e_drhob(i, j, k)*drho1a(idir)%array(i, j, k)*rho1a(i, j, k)/s
    3758              :                            END DO
    3759              :                         END DO
    3760              :                      END DO
    3761              : !$OMP             END PARALLEL DO
    3762              :                   END IF
    3763              :                END DO
    3764              : 
    3765              :                ! partial integration: v_xc = v_xc - \nabla \cdot vdrho_r
    3766            0 :                DO ispin = 1, nspins
    3767            0 :                   CALL xc_pw_divergence(xc_deriv_method_id, v_drho_r(:, ispin), tmp_g, vxc_g, v_xc(ispin))
    3768              :                END DO ! ispin
    3769              :             END IF ! ALDA0
    3770              : 
    3771            0 :             DO idir = 1, 3
    3772            0 :                DEALLOCATE (drho(idir)%array)
    3773            0 :                DEALLOCATE (drho1(idir)%array)
    3774              :             END DO
    3775              : 
    3776            0 :             DO ispin = 1, nspins
    3777            0 :                CALL deallocate_pw(v_drhoa(ispin), pw_pool)
    3778            0 :                CALL deallocate_pw(v_drhob(ispin), pw_pool)
    3779              :             END DO
    3780              : 
    3781            0 :             DEALLOCATE (v_drhoa, v_drhob)
    3782              : 
    3783              :          END IF ! gradient_f
    3784              : 
    3785              :       ELSE
    3786              : 
    3787              :          !-----------------!
    3788              :          ! restricted case !
    3789              :          !-----------------!
    3790            0 :          CPABORT("Exchange-correlation's analytic third derivative not implemented")
    3791              : 
    3792              :       END IF
    3793              : 
    3794            0 :       IF (gradient_f) THEN
    3795              : 
    3796            0 :          DO ispin = 1, nspins
    3797            0 :             CALL deallocate_pw(v_drho(ispin), pw_pool)
    3798            0 :             DO idir = 1, 3
    3799            0 :                CALL deallocate_pw(v_drho_r(idir, ispin), pw_pool)
    3800              :             END DO
    3801              :          END DO
    3802            0 :          DEALLOCATE (v_drho, v_drho_r)
    3803              : 
    3804              :       END IF
    3805              : 
    3806            0 :       IF (ASSOCIATED(tmp_g%pw_grid) .AND. ASSOCIATED(pw_pool)) THEN
    3807            0 :          CALL pw_pool%give_back_pw(tmp_g)
    3808              :       END IF
    3809              : 
    3810            0 :       IF (ASSOCIATED(vxc_g%pw_grid) .AND. ASSOCIATED(pw_pool)) THEN
    3811            0 :          CALL pw_pool%give_back_pw(vxc_g)
    3812              :       END IF
    3813              : 
    3814            0 :       CALL timestop(handle)
    3815            0 :    END SUBROUTINE xc_calc_3rd_deriv_analytical
    3816              : 
    3817              : ! **************************************************************************************************
    3818              : !> \brief allocates grids using pw_pool (if associated) or with bounds
    3819              : !> \param pw ...
    3820              : !> \param pw_pool ...
    3821              : !> \param bo ...
    3822              : ! **************************************************************************************************
    3823       101546 :    SUBROUTINE allocate_pw(pw, pw_pool, bo)
    3824              :       TYPE(pw_r3d_rs_type), INTENT(OUT)                         :: pw
    3825              :       TYPE(pw_pool_type), INTENT(IN), POINTER            :: pw_pool
    3826              :       INTEGER, DIMENSION(2, 3), INTENT(IN)               :: bo
    3827              : 
    3828       101546 :       IF (ASSOCIATED(pw_pool)) THEN
    3829        65082 :          CALL pw_pool%create_pw(pw)
    3830        65082 :          CALL pw_zero(pw)
    3831              :       ELSE
    3832       182320 :          ALLOCATE (pw%array(bo(1, 1):bo(2, 1), bo(1, 2):bo(2, 2), bo(1, 3):bo(2, 3)))
    3833     93056128 :          pw%array = 0.0_dp
    3834              :       END IF
    3835              : 
    3836       101546 :    END SUBROUTINE allocate_pw
    3837              : 
    3838              : ! **************************************************************************************************
    3839              : !> \brief deallocates grid allocated with allocate_pw
    3840              : !> \param pw ...
    3841              : !> \param pw_pool ...
    3842              : ! **************************************************************************************************
    3843       101546 :    SUBROUTINE deallocate_pw(pw, pw_pool)
    3844              :       TYPE(pw_r3d_rs_type), INTENT(INOUT)                       :: pw
    3845              :       TYPE(pw_pool_type), INTENT(IN), POINTER            :: pw_pool
    3846              : 
    3847       101546 :       IF (ASSOCIATED(pw_pool)) THEN
    3848        65082 :          CALL pw_pool%give_back_pw(pw)
    3849              :       ELSE
    3850        36464 :          CALL pw%release()
    3851              :       END IF
    3852              : 
    3853       101546 :    END SUBROUTINE deallocate_pw
    3854              : 
    3855              : ! **************************************************************************************************
    3856              : !> \brief updates virial from first derivative w.r.t. norm_drho
    3857              : !> \param virial_pw ...
    3858              : !> \param drho ...
    3859              : !> \param drho1 ...
    3860              : !> \param deriv_data ...
    3861              : !> \param virial_xc ...
    3862              : ! **************************************************************************************************
    3863          304 :    SUBROUTINE virial_drho_drho1(virial_pw, drho, drho1, deriv_data, virial_xc)
    3864              :       TYPE(pw_r3d_rs_type), INTENT(IN)                          :: virial_pw
    3865              :       TYPE(cp_3d_r_cp_type), DIMENSION(3), INTENT(IN)     :: drho, drho1
    3866              :       REAL(KIND=dp), DIMENSION(:, :, :), INTENT(IN)      :: deriv_data
    3867              :       REAL(KIND=dp), DIMENSION(3, 3), INTENT(INOUT)      :: virial_xc
    3868              : 
    3869              :       INTEGER                                            :: idir, jdir
    3870              :       REAL(KIND=dp)                                      :: tmp
    3871              : 
    3872         1216 :       DO idir = 1, 3
    3873          912 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(drho,idir,virial_pw,deriv_data)
    3874              :          virial_pw%array(:, :, :) = drho(idir)%array(:, :, :)*deriv_data(:, :, :)
    3875              : !$OMP END PARALLEL WORKSHARE
    3876         3952 :          DO jdir = 1, 3
    3877              :             tmp = virial_pw%pw_grid%dvol*accurate_dot_product(virial_pw%array(:, :, :), &
    3878         2736 :                                                               drho1(jdir)%array(:, :, :))
    3879         2736 :             virial_xc(jdir, idir) = virial_xc(jdir, idir) + tmp
    3880         3648 :             virial_xc(idir, jdir) = virial_xc(idir, jdir) + tmp
    3881              :          END DO
    3882              :       END DO
    3883              : 
    3884          304 :    END SUBROUTINE virial_drho_drho1
    3885              : 
    3886              : ! **************************************************************************************************
    3887              : !> \brief Adds virial contribution from second order potential parts
    3888              : !> \param virial_pw ...
    3889              : !> \param drho ...
    3890              : !> \param v_drho ...
    3891              : !> \param virial_xc ...
    3892              : ! **************************************************************************************************
    3893          298 :    SUBROUTINE virial_drho_drho(virial_pw, drho, v_drho, virial_xc)
    3894              :       TYPE(pw_r3d_rs_type), INTENT(IN)                          :: virial_pw
    3895              :       TYPE(cp_3d_r_cp_type), DIMENSION(3), INTENT(IN)     :: drho
    3896              :       TYPE(pw_r3d_rs_type), INTENT(IN)                        :: v_drho
    3897              :       REAL(KIND=dp), DIMENSION(3, 3), INTENT(INOUT)      :: virial_xc
    3898              : 
    3899              :       INTEGER                                            :: idir, jdir
    3900              :       REAL(KIND=dp)                                      :: tmp
    3901              : 
    3902         1192 :       DO idir = 1, 3
    3903          894 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(drho,idir,v_drho,virial_pw)
    3904              :          virial_pw%array(:, :, :) = drho(idir)%array(:, :, :)*v_drho%array(:, :, :)
    3905              : !$OMP END PARALLEL WORKSHARE
    3906         2980 :          DO jdir = 1, idir
    3907              :             tmp = -virial_pw%pw_grid%dvol*accurate_dot_product(virial_pw%array(:, :, :), &
    3908         1788 :                                                                drho(jdir)%array(:, :, :))
    3909         1788 :             virial_xc(jdir, idir) = virial_xc(jdir, idir) + tmp
    3910         2682 :             virial_xc(idir, jdir) = virial_xc(jdir, idir)
    3911              :          END DO
    3912              :       END DO
    3913              : 
    3914          298 :    END SUBROUTINE virial_drho_drho
    3915              : 
    3916              : ! **************************************************************************************************
    3917              : !> \brief ...
    3918              : !> \param rho_r ...
    3919              : !> \param pw_pool ...
    3920              : !> \param virial_xc ...
    3921              : !> \param deriv_data ...
    3922              : ! **************************************************************************************************
    3923          150 :    SUBROUTINE virial_laplace(rho_r, pw_pool, virial_xc, deriv_data)
    3924              :       TYPE(pw_r3d_rs_type), TARGET :: rho_r
    3925              :       TYPE(pw_pool_type), POINTER, INTENT(IN) :: pw_pool
    3926              :       REAL(KIND=dp), DIMENSION(3, 3), INTENT(INOUT) :: virial_xc
    3927              :       REAL(KIND=dp), DIMENSION(:, :, :), INTENT(IN) :: deriv_data
    3928              : 
    3929              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'virial_laplace'
    3930              : 
    3931              :       INTEGER :: handle, idir, jdir
    3932              :       TYPE(pw_r3d_rs_type), POINTER :: virial_pw
    3933              :       TYPE(pw_c1d_gs_type), POINTER :: tmp_g, rho_g
    3934              :       INTEGER, DIMENSION(3) :: my_deriv
    3935              : 
    3936          150 :       CALL timeset(routineN, handle)
    3937              : 
    3938          150 :       NULLIFY (virial_pw, tmp_g, rho_g)
    3939          150 :       ALLOCATE (virial_pw, tmp_g, rho_g)
    3940          150 :       CALL pw_pool%create_pw(virial_pw)
    3941          150 :       CALL pw_pool%create_pw(tmp_g)
    3942          150 :       CALL pw_pool%create_pw(rho_g)
    3943          150 :       CALL pw_zero(virial_pw)
    3944          150 :       CALL pw_transfer(rho_r, rho_g)
    3945          600 :       DO idir = 1, 3
    3946         1500 :          DO jdir = idir, 3
    3947          900 :             CALL pw_copy(rho_g, tmp_g)
    3948              : 
    3949          900 :             my_deriv = 0
    3950          900 :             my_deriv(idir) = 1
    3951          900 :             my_deriv(jdir) = my_deriv(jdir) + 1
    3952              : 
    3953          900 :             CALL pw_derive(tmp_g, my_deriv)
    3954          900 :             CALL pw_transfer(tmp_g, virial_pw)
    3955              :             virial_xc(idir, jdir) = virial_xc(idir, jdir) - 2.0_dp*virial_pw%pw_grid%dvol* &
    3956              :                                     accurate_dot_product(virial_pw%array(:, :, :), &
    3957          900 :                                                          deriv_data(:, :, :))
    3958         1350 :             virial_xc(jdir, idir) = virial_xc(idir, jdir)
    3959              :          END DO
    3960              :       END DO
    3961          150 :       CALL pw_pool%give_back_pw(virial_pw)
    3962          150 :       CALL pw_pool%give_back_pw(tmp_g)
    3963          150 :       CALL pw_pool%give_back_pw(rho_g)
    3964          150 :       DEALLOCATE (virial_pw, tmp_g, rho_g)
    3965              : 
    3966          150 :       CALL timestop(handle)
    3967              : 
    3968          150 :    END SUBROUTINE virial_laplace
    3969              : 
    3970              : ! **************************************************************************************************
    3971              : !> \brief Prepare objects for the calculation of the 2nd derivatives of the density functional.
    3972              : !>      The calculation must then be performed with xc_calc_2nd_deriv.
    3973              : !> \param deriv_set object containing the XC derivatives (out)
    3974              : !> \param rho_set object that will contain the density at which the
    3975              : !>        derivatives were calculated
    3976              : !> \param rho_r the place where you evaluate the derivative
    3977              : !> \param pw_pool the pool for the grids
    3978              : !> \param xc_section which functional should be used and how to calculate it
    3979              : !> \param tau_r kinetic energy density in real space
    3980              : ! **************************************************************************************************
    3981        12660 :    SUBROUTINE xc_prep_2nd_deriv(deriv_set, &
    3982              :                                 rho_set, rho_r, pw_pool, xc_section, tau_r)
    3983              : 
    3984              :       TYPE(xc_derivative_set_type)                       :: deriv_set
    3985              :       TYPE(xc_rho_set_type)                              :: rho_set
    3986              :       TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER               :: rho_r
    3987              :       TYPE(pw_pool_type), POINTER                        :: pw_pool
    3988              :       TYPE(section_vals_type), POINTER                   :: xc_section
    3989              :       TYPE(pw_r3d_rs_type), DIMENSION(:), OPTIONAL, POINTER     :: tau_r
    3990              : 
    3991              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'xc_prep_2nd_deriv'
    3992              : 
    3993              :       INTEGER                                            :: handle, nspins
    3994              :       LOGICAL                                            :: lsd
    3995        12660 :       TYPE(pw_c1d_gs_type), DIMENSION(:), POINTER               :: rho_g
    3996        12660 :       TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: tau
    3997              : 
    3998        12660 :       CALL timeset(routineN, handle)
    3999              : 
    4000        12660 :       CPASSERT(ASSOCIATED(xc_section))
    4001        12660 :       CPASSERT(ASSOCIATED(pw_pool))
    4002              : 
    4003        12660 :       nspins = SIZE(rho_r)
    4004        12660 :       lsd = (nspins /= 1)
    4005              : 
    4006        12660 :       NULLIFY (rho_g, tau)
    4007        12660 :       IF (PRESENT(tau_r)) &
    4008        11996 :          tau => tau_r
    4009              : 
    4010        12660 :       IF (section_get_lval(xc_section, "2ND_DERIV_ANALYTICAL")) THEN
    4011              :          CALL xc_rho_set_and_dset_create(rho_set, deriv_set, 2, &
    4012              :                                          rho_r, rho_g, tau, xc_section, pw_pool, &
    4013        12576 :                                          calc_potential=.TRUE.)
    4014              :       ELSE
    4015              :          CALL xc_rho_set_and_dset_create(rho_set, deriv_set, 1, &
    4016              :                                          rho_r, rho_g, tau, xc_section, pw_pool, &
    4017           84 :                                          calc_potential=.TRUE.)
    4018              :       END IF
    4019              : 
    4020        12660 :       CALL timestop(handle)
    4021              : 
    4022        12660 :    END SUBROUTINE xc_prep_2nd_deriv
    4023              : 
    4024              : ! **************************************************************************************************
    4025              : !> \brief Prepare deriv_set for the calculation of the 3rd derivatives of the density functional.
    4026              : !>      The calculation must then be performed with xc_calc_3rd_deriv.
    4027              : !> \param deriv_set object containing the XC derivatives (out)
    4028              : !> \param rho_set object that will contain the density at which the
    4029              : !>        derivatives were calculated
    4030              : !> \param rho_r the place where you evaluate the derivative
    4031              : !> \param pw_pool the pool for the grids
    4032              : !> \param xc_section which functional should be used and how to calculate it
    4033              : !> \param tau_r kinetic energy density in real space
    4034              : !> \param do_sf Flag to activate the noncollinear kernel for spin flip calculations
    4035              : !> \par History
    4036              : !>    * 07.2024 Created [LHS]
    4037              : ! **************************************************************************************************
    4038            0 :    SUBROUTINE xc_prep_3rd_deriv(deriv_set, rho_set, rho_r, pw_pool, xc_section, tau_r, do_sf)
    4039              : 
    4040              :       TYPE(xc_derivative_set_type)                       :: deriv_set
    4041              :       TYPE(xc_rho_set_type)                              :: rho_set
    4042              :       TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER               :: rho_r
    4043              :       TYPE(pw_pool_type), POINTER                        :: pw_pool
    4044              :       TYPE(section_vals_type), POINTER                   :: xc_section
    4045              :       TYPE(pw_r3d_rs_type), DIMENSION(:), OPTIONAL, POINTER     :: tau_r
    4046              :       LOGICAL, OPTIONAL                                  :: do_sf
    4047              : 
    4048              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'xc_prep_3rd_deriv'
    4049              : 
    4050              :       INTEGER                                            :: handle, nspins
    4051              :       LOGICAL                                            :: lsd, my_do_sf
    4052            0 :       TYPE(pw_c1d_gs_type), DIMENSION(:), POINTER        :: rho_g
    4053            0 :       TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER        :: tau
    4054              : 
    4055            0 :       CALL timeset(routineN, handle)
    4056              : 
    4057            0 :       CPASSERT(ASSOCIATED(xc_section))
    4058            0 :       CPASSERT(ASSOCIATED(pw_pool))
    4059              : 
    4060            0 :       nspins = SIZE(rho_r)
    4061            0 :       lsd = (nspins /= 1)
    4062              : 
    4063            0 :       NULLIFY (rho_g, tau)
    4064            0 :       IF (PRESENT(tau_r)) &
    4065            0 :          tau => tau_r
    4066              : 
    4067            0 :       my_do_sf = .FALSE.
    4068            0 :       IF (PRESENT(do_sf)) my_do_sf = do_sf
    4069              : 
    4070            0 :       IF (do_sf) THEN
    4071              :          CALL xc_rho_set_and_dset_create(rho_set, deriv_set, 2, &
    4072              :                                          rho_r, rho_g, tau, xc_section, pw_pool, &
    4073            0 :                                          calc_potential=.TRUE.)
    4074              :       ELSE
    4075              :          CALL xc_rho_set_and_dset_create(rho_set, deriv_set, 3, &
    4076              :                                          rho_r, rho_g, tau, xc_section, pw_pool, &
    4077            0 :                                          calc_potential=.TRUE.)
    4078              :       END IF
    4079              : 
    4080            0 :       CALL timestop(handle)
    4081              : 
    4082            0 :    END SUBROUTINE xc_prep_3rd_deriv
    4083              : 
    4084              : ! **************************************************************************************************
    4085              : !> \brief divides derivatives from deriv_set by norm_drho
    4086              : !> \param deriv_set ...
    4087              : !> \param rho_set ...
    4088              : !> \param lsd ...
    4089              : ! **************************************************************************************************
    4090       147945 :    SUBROUTINE divide_by_norm_drho(deriv_set, rho_set, lsd)
    4091              : 
    4092              :       TYPE(xc_derivative_set_type), INTENT(INOUT)        :: deriv_set
    4093              :       TYPE(xc_rho_set_type), INTENT(IN)                  :: rho_set
    4094              :       LOGICAL, INTENT(IN)                                :: lsd
    4095              : 
    4096       147945 :       INTEGER, DIMENSION(:), POINTER                     :: split_desc
    4097              :       INTEGER                                            :: idesc
    4098              :       INTEGER, DIMENSION(2, 3)                           :: bo
    4099              :       REAL(KIND=dp)                                      :: drho_cutoff
    4100       147945 :       REAL(KIND=dp), DIMENSION(:, :, :), POINTER         :: norm_drho, norm_drhoa, norm_drhob
    4101      1775340 :       TYPE(cp_3d_r_cp_type), DIMENSION(3)                 :: drho, drhoa, drhob
    4102              :       TYPE(cp_sll_xc_deriv_type), POINTER                :: pos
    4103              :       TYPE(xc_derivative_type), POINTER                  :: deriv_att
    4104              : 
    4105              : ! check for unknown derivatives and divide by norm_drho where necessary
    4106              : 
    4107      1479450 :       bo = rho_set%local_bounds
    4108              :       CALL xc_rho_set_get(rho_set, drho_cutoff=drho_cutoff, norm_drho=norm_drho, &
    4109              :                           norm_drhoa=norm_drhoa, norm_drhob=norm_drhob, &
    4110       147945 :                           drho=drho, drhoa=drhoa, drhob=drhob, can_return_null=.TRUE.)
    4111              : 
    4112       147945 :       pos => deriv_set%derivs
    4113       635029 :       DO WHILE (cp_sll_xc_deriv_next(pos, el_att=deriv_att))
    4114       487084 :          CALL xc_derivative_get(deriv_att, split_desc=split_desc)
    4115      1042504 :          DO idesc = 1, SIZE(split_desc)
    4116       487084 :             SELECT CASE (split_desc(idesc))
    4117              :             CASE (deriv_norm_drho)
    4118       123329 :                IF (ASSOCIATED(norm_drho)) THEN
    4119       123329 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(deriv_att,norm_drho,drho_cutoff)
    4120              :                   deriv_att%deriv_data(:, :, :) = deriv_att%deriv_data(:, :, :)/ &
    4121              :                                                   MAX(norm_drho(:, :, :), drho_cutoff)
    4122              : !$OMP END PARALLEL WORKSHARE
    4123            0 :                ELSE IF (ASSOCIATED(drho(1)%array)) THEN
    4124            0 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(deriv_att,drho,drho_cutoff)
    4125              :                   deriv_att%deriv_data(:, :, :) = deriv_att%deriv_data(:, :, :)/ &
    4126              :                                                   MAX(SQRT(drho(1)%array(:, :, :)**2 + &
    4127              :                                                            drho(2)%array(:, :, :)**2 + &
    4128              :                                                            drho(3)%array(:, :, :)**2), drho_cutoff)
    4129              : !$OMP END PARALLEL WORKSHARE
    4130            0 :                ELSE IF (ASSOCIATED(drhoa(1)%array) .AND. ASSOCIATED(drhob(1)%array)) THEN
    4131            0 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(deriv_att,drhoa,drhob,drho_cutoff)
    4132              :                   deriv_att%deriv_data(:, :, :) = deriv_att%deriv_data(:, :, :)/ &
    4133              :                                                   MAX(SQRT((drhoa(1)%array(:, :, :) + drhob(1)%array(:, :, :))**2 + &
    4134              :                                                            (drhoa(2)%array(:, :, :) + drhob(2)%array(:, :, :))**2 + &
    4135              :                                                            (drhoa(3)%array(:, :, :) + drhob(3)%array(:, :, :))**2), drho_cutoff)
    4136              : !$OMP END PARALLEL WORKSHARE
    4137              :                ELSE
    4138            0 :                   CPABORT("Normalization of derivative requires any of norm_drho, drho or drhoa+drhob!")
    4139              :                END IF
    4140              :             CASE (deriv_norm_drhoa)
    4141        21422 :                IF (ASSOCIATED(norm_drhoa)) THEN
    4142        21422 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(deriv_att,norm_drhoa,drho_cutoff)
    4143              :                   deriv_att%deriv_data(:, :, :) = deriv_att%deriv_data(:, :, :)/ &
    4144              :                                                   MAX(norm_drhoa(:, :, :), drho_cutoff)
    4145              : !$OMP END PARALLEL WORKSHARE
    4146            0 :                ELSE IF (ASSOCIATED(drhoa(1)%array)) THEN
    4147            0 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(deriv_att,drhoa,drho_cutoff)
    4148              :                   deriv_att%deriv_data(:, :, :) = deriv_att%deriv_data(:, :, :)/ &
    4149              :                                                   MAX(SQRT(drhoa(1)%array(:, :, :)**2 + &
    4150              :                                                            drhoa(2)%array(:, :, :)**2 + &
    4151              :                                                            drhoa(3)%array(:, :, :)**2), drho_cutoff)
    4152              : !$OMP END PARALLEL WORKSHARE
    4153              :                ELSE
    4154            0 :                   CPABORT("Normalization of derivative requires any of norm_drhoa or drhoa!")
    4155              :                END IF
    4156              :             CASE (deriv_norm_drhob)
    4157        21418 :                IF (ASSOCIATED(norm_drhob)) THEN
    4158        21418 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(deriv_att,norm_drhob,drho_cutoff)
    4159              :                   deriv_att%deriv_data(:, :, :) = deriv_att%deriv_data(:, :, :)/ &
    4160              :                                                   MAX(norm_drhob(:, :, :), drho_cutoff)
    4161              : !$OMP END PARALLEL WORKSHARE
    4162            0 :                ELSE IF (ASSOCIATED(drhob(1)%array)) THEN
    4163            0 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(deriv_att,drhob,drho_cutoff)
    4164              :                   deriv_att%deriv_data(:, :, :) = deriv_att%deriv_data(:, :, :)/ &
    4165              :                                                   MAX(SQRT(drhob(1)%array(:, :, :)**2 + &
    4166              :                                                            drhob(2)%array(:, :, :)**2 + &
    4167              :                                                            drhob(3)%array(:, :, :)**2), drho_cutoff)
    4168              : !$OMP END PARALLEL WORKSHARE
    4169              :                ELSE
    4170            0 :                   CPABORT("Normalization of derivative requires any of norm_drhob or drhob!")
    4171              :                END IF
    4172              :             CASE (deriv_rho, deriv_tau, deriv_laplace_rho)
    4173       167518 :                IF (lsd) &
    4174            0 :                   CPABORT(TRIM(id_to_desc(split_desc(idesc)))//" not handled in lsd!'")
    4175              :             CASE (deriv_rhoa, deriv_rhob, deriv_tau_a, deriv_tau_b, deriv_laplace_rhoa, deriv_laplace_rhob)
    4176              :             CASE default
    4177       407475 :                CPABORT("Unknown derivative id")
    4178              :             END SELECT
    4179              :          END DO
    4180              :       END DO
    4181              : 
    4182       147945 :    END SUBROUTINE divide_by_norm_drho
    4183              : 
    4184              : ! **************************************************************************************************
    4185              : !> \brief allocates and calculates drho from given spin densities drhoa, drhob
    4186              : !> \param drho ...
    4187              : !> \param drhoa ...
    4188              : !> \param drhob ...
    4189              : ! **************************************************************************************************
    4190        20936 :    SUBROUTINE calc_drho_from_ab(drho, drhoa, drhob)
    4191              :       TYPE(cp_3d_r_cp_type), DIMENSION(3), INTENT(OUT)    :: drho
    4192              :       TYPE(cp_3d_r_cp_type), DIMENSION(3), INTENT(IN)     :: drhoa, drhob
    4193              : 
    4194              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'calc_drho_from_ab'
    4195              : 
    4196              :       INTEGER                                            :: handle, idir
    4197              : 
    4198         5234 :       CALL timeset(routineN, handle)
    4199              : 
    4200        20936 :       DO idir = 1, 3
    4201        15702 :          NULLIFY (drho(idir)%array)
    4202              :          ALLOCATE (drho(idir)%array(LBOUND(drhoa(1)%array, 1):UBOUND(drhoa(1)%array, 1), &
    4203              :                                     LBOUND(drhoa(1)%array, 2):UBOUND(drhoa(1)%array, 2), &
    4204       188424 :                                     LBOUND(drhoa(1)%array, 3):UBOUND(drhoa(1)%array, 3)))
    4205        20936 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(drho,drhoa,drhob,idir)
    4206              :          drho(idir)%array(:, :, :) = drhoa(idir)%array(:, :, :) + drhob(idir)%array(:, :, :)
    4207              : !$OMP END PARALLEL WORKSHARE
    4208              :       END DO
    4209              : 
    4210         5234 :       CALL timestop(handle)
    4211              : 
    4212         5234 :    END SUBROUTINE calc_drho_from_ab
    4213              : 
    4214              : ! **************************************************************************************************
    4215              : !> \brief allocates and calculates drho from given spin densities drhoa, drhob
    4216              : !> \param drho ...
    4217              : !> \param drhoa ...
    4218              : !> \param drhob ...
    4219              : ! **************************************************************************************************
    4220         1048 :    SUBROUTINE calc_drho_from_a(drho, drhoa)
    4221              :       TYPE(cp_3d_r_cp_type), DIMENSION(3), INTENT(OUT)    :: drho
    4222              :       TYPE(cp_3d_r_cp_type), DIMENSION(3), INTENT(IN)     :: drhoa
    4223              : 
    4224              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'calc_drho_from_a'
    4225              : 
    4226              :       INTEGER                                            :: handle, idir
    4227              : 
    4228          262 :       CALL timeset(routineN, handle)
    4229              : 
    4230         1048 :       DO idir = 1, 3
    4231          786 :          NULLIFY (drho(idir)%array)
    4232              :          ALLOCATE (drho(idir)%array(LBOUND(drhoa(1)%array, 1):UBOUND(drhoa(1)%array, 1), &
    4233              :                                     LBOUND(drhoa(1)%array, 2):UBOUND(drhoa(1)%array, 2), &
    4234         9432 :                                     LBOUND(drhoa(1)%array, 3):UBOUND(drhoa(1)%array, 3)))
    4235         1048 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(drho,drhoa,idir)
    4236              :          drho(idir)%array(:, :, :) = drhoa(idir)%array(:, :, :)
    4237              : !$OMP END PARALLEL WORKSHARE
    4238              :       END DO
    4239              : 
    4240          262 :       CALL timestop(handle)
    4241              : 
    4242          262 :    END SUBROUTINE calc_drho_from_a
    4243              : 
    4244              : ! **************************************************************************************************
    4245              : !> \brief allocates and calculates dot products of two density gradients
    4246              : !> \param dr1dr ...
    4247              : !> \param drho ...
    4248              : !> \param drho1 ...
    4249              : ! **************************************************************************************************
    4250        25740 :    SUBROUTINE prepare_dr1dr(dr1dr, drho, drho1)
    4251              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :), &
    4252              :          INTENT(OUT)                                     :: dr1dr
    4253              :       TYPE(cp_3d_r_cp_type), DIMENSION(3), INTENT(IN)     :: drho, drho1
    4254              : 
    4255              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'prepare_dr1dr'
    4256              : 
    4257              :       INTEGER                                            :: handle, idir
    4258              : 
    4259        25740 :       CALL timeset(routineN, handle)
    4260              : 
    4261            0 :       ALLOCATE (dr1dr(LBOUND(drho(1)%array, 1):UBOUND(drho(1)%array, 1), &
    4262              :                       LBOUND(drho(1)%array, 2):UBOUND(drho(1)%array, 2), &
    4263       308880 :                       LBOUND(drho(1)%array, 3):UBOUND(drho(1)%array, 3)))
    4264              : 
    4265        25740 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(dr1dr,drho,drho1)
    4266              :       dr1dr(:, :, :) = drho(1)%array(:, :, :)*drho1(1)%array(:, :, :)
    4267              : !$OMP END PARALLEL WORKSHARE
    4268        77220 :       DO idir = 2, 3
    4269        77220 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(dr1dr,drho,drho1,idir)
    4270              :          dr1dr(:, :, :) = dr1dr(:, :, :) + drho(idir)%array(:, :, :)*drho1(idir)%array(:, :, :)
    4271              : !$OMP END PARALLEL WORKSHARE
    4272              :       END DO
    4273              : 
    4274        25740 :       CALL timestop(handle)
    4275              : 
    4276        25740 :    END SUBROUTINE prepare_dr1dr
    4277              : 
    4278              : ! **************************************************************************************************
    4279              : !> \brief allocates and calculates dot product of two densities for triplets
    4280              : !> \param dr1dr ...
    4281              : !> \param drhoa ...
    4282              : !> \param drhob ...
    4283              : !> \param drho1a ...
    4284              : !> \param drho1b ...
    4285              : !> \param fac ...
    4286              : ! **************************************************************************************************
    4287          710 :    SUBROUTINE prepare_dr1dr_ab(dr1dr, drhoa, drhob, drho1a, drho1b, fac)
    4288              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :), &
    4289              :          INTENT(OUT)                                     :: dr1dr
    4290              :       TYPE(cp_3d_r_cp_type), DIMENSION(3), INTENT(IN)    :: drhoa, drhob, drho1a, drho1b
    4291              :       REAL(KIND=dp), INTENT(IN)                          :: fac
    4292              : 
    4293              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'prepare_dr1dr_ab'
    4294              : 
    4295              :       INTEGER                                            :: handle, idir
    4296              : 
    4297          710 :       CALL timeset(routineN, handle)
    4298              : 
    4299            0 :       ALLOCATE (dr1dr(LBOUND(drhoa(1)%array, 1):UBOUND(drhoa(1)%array, 1), &
    4300              :                       LBOUND(drhoa(1)%array, 2):UBOUND(drhoa(1)%array, 2), &
    4301         8520 :                       LBOUND(drhoa(1)%array, 3):UBOUND(drhoa(1)%array, 3)))
    4302              : 
    4303          710 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(fac,dr1dr,drho1a,drho1b,drhoa,drhob)
    4304              :       dr1dr(:, :, :) = drhoa(1)%array(:, :, :)*(drho1a(1)%array(:, :, :) + &
    4305              :                                                 fac*drho1b(1)%array(:, :, :)) + &
    4306              :                        drhob(1)%array(:, :, :)*(fac*drho1a(1)%array(:, :, :) + &
    4307              :                                                 drho1b(1)%array(:, :, :))
    4308              : !$OMP END PARALLEL WORKSHARE
    4309         2130 :       DO idir = 2, 3
    4310         2130 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(fac,dr1dr,drho1a,drho1b,drhoa,drhob,idir)
    4311              :          dr1dr(:, :, :) = dr1dr(:, :, :) + &
    4312              :                           drhoa(idir)%array(:, :, :)*(drho1a(idir)%array(:, :, :) + &
    4313              :                                                       fac*drho1b(idir)%array(:, :, :)) + &
    4314              :                           drhob(idir)%array(:, :, :)*(fac*drho1a(idir)%array(:, :, :) + &
    4315              :                                                       drho1b(idir)%array(:, :, :))
    4316              : !$OMP END PARALLEL WORKSHARE
    4317              :       END DO
    4318              : 
    4319          710 :       CALL timestop(handle)
    4320              : 
    4321          710 :    END SUBROUTINE prepare_dr1dr_ab
    4322              : 
    4323              : ! **************************************************************************************************
    4324              : !> \brief checks for gradients
    4325              : !> \param deriv_set ...
    4326              : !> \param lsd ...
    4327              : !> \param gradient_f ...
    4328              : !> \param tau_f ...
    4329              : !> \param laplace_f ...
    4330              : ! **************************************************************************************************
    4331       146479 :    SUBROUTINE check_for_derivatives(deriv_set, lsd, rho_f, gradient_f, tau_f, laplace_f)
    4332              :       TYPE(xc_derivative_set_type), INTENT(IN)           :: deriv_set
    4333              :       LOGICAL, INTENT(IN)                                :: lsd
    4334              :       LOGICAL, INTENT(OUT)                               :: rho_f, gradient_f, tau_f, laplace_f
    4335              : 
    4336              :       CHARACTER(len=*), PARAMETER :: routineN = 'check_for_derivatives'
    4337              : 
    4338              :       INTEGER                                            :: handle, iorder, order
    4339       146479 :       INTEGER, DIMENSION(:), POINTER                     :: split_desc
    4340              :       TYPE(cp_sll_xc_deriv_type), POINTER                :: pos
    4341              :       TYPE(xc_derivative_type), POINTER                  :: deriv_att
    4342              : 
    4343       146479 :       CALL timeset(routineN, handle)
    4344              : 
    4345       146479 :       rho_f = .FALSE.
    4346       146479 :       gradient_f = .FALSE.
    4347       146479 :       tau_f = .FALSE.
    4348       146479 :       laplace_f = .FALSE.
    4349              :       ! check for unknown derivatives
    4350       146479 :       pos => deriv_set%derivs
    4351       676273 :       DO WHILE (cp_sll_xc_deriv_next(pos, el_att=deriv_att))
    4352              :          CALL xc_derivative_get(deriv_att, order=order, &
    4353       529794 :                                 split_desc=split_desc)
    4354       676273 :          IF (lsd) THEN
    4355       340529 :             DO iorder = 1, size(split_desc)
    4356       166793 :                SELECT CASE (split_desc(iorder))
    4357              :                CASE (deriv_rhoa, deriv_rhob)
    4358        89684 :                   rho_f = .TRUE.
    4359              :                CASE (deriv_norm_drho, deriv_norm_drhoa, deriv_norm_drhob)
    4360        79980 :                   gradient_f = .TRUE.
    4361              :                CASE (deriv_tau_a, deriv_tau_b)
    4362         2760 :                   tau_f = .TRUE.
    4363              :                CASE (deriv_laplace_rhoa, deriv_laplace_rhob)
    4364         1312 :                   laplace_f = .TRUE.
    4365              :                CASE (deriv_rho, deriv_tau, deriv_laplace_rho)
    4366            0 :                   CPABORT("Derivative not handled in lsd!")
    4367              :                CASE default
    4368       173736 :                   CPABORT("Unknown derivative id")
    4369              :                END SELECT
    4370              :             END DO
    4371              :          ELSE
    4372       674192 :             DO iorder = 1, size(split_desc)
    4373       363001 :                SELECT CASE (split_desc(iorder))
    4374              :                CASE (deriv_rho)
    4375       183770 :                   rho_f = .TRUE.
    4376              :                CASE (deriv_tau)
    4377         4996 :                   tau_f = .TRUE.
    4378              :                CASE (deriv_norm_drho)
    4379       120987 :                   gradient_f = .TRUE.
    4380              :                CASE (deriv_laplace_rho)
    4381         1438 :                   laplace_f = .TRUE.
    4382              :                CASE default
    4383       311191 :                   CPABORT("Unknown derivative id")
    4384              :                END SELECT
    4385              :             END DO
    4386              :          END IF
    4387              :       END DO
    4388              : 
    4389       146479 :       CALL timestop(handle)
    4390              : 
    4391       146479 :    END SUBROUTINE check_for_derivatives
    4392              : 
    4393              : END MODULE xc
        

Generated by: LCOV version 2.0-1