LCOV - code coverage report
Current view: top level - src/xc - xc.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:32ddf85) Lines: 898 1278 70.3 %
Date: 2025-05-17 08:08:58 Functions: 28 30 93.3 %

          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, &
      76             :              xc_calc_2nd_deriv, xc_prep_2nd_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        7568 :    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       15136 :                                        calc_potential=.FALSE.)
     101        7568 :       res = (needs%tau_spin .OR. needs%tau)
     102             : 
     103        7568 :    END FUNCTION
     104             : 
     105             : ! **************************************************************************************************
     106             : !> \brief ...
     107             : !> \param xc_fun_section ...
     108             : !> \param lsd ...
     109             : !> \return ...
     110             : ! **************************************************************************************************
     111        7584 :    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       15168 :                                        calc_potential=.FALSE.)
     121        7584 :       res = (needs%norm_drho .OR. needs%norm_drho_spin)
     122             : 
     123        7584 :    END FUNCTION
     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      217994 :    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      108997 :       CPASSERT(ASSOCIATED(rho_r))
     164      108997 :       CPASSERT(ASSOCIATED(xc_section))
     165      108997 :       CPASSERT(.NOT. ASSOCIATED(vxc_rho))
     166      108997 :       CPASSERT(.NOT. ASSOCIATED(vxc_tau))
     167             : 
     168      108997 :       virial_xc = 0.0_dp
     169             : 
     170             :       CALL section_vals_val_get(xc_section, "FUNCTIONAL_ROUTINE", &
     171      108997 :                                 i_val=f_routine)
     172      108997 :       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      108997 :                                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      108997 :                                         xc_section=xc_section, pw_pool=pw_pool)
     187             :       CASE default
     188             :       END SELECT
     189             : 
     190      108997 :    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      267142 :    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      133571 :       CALL timeset(routineN, handle)
     859             : 
     860      133571 :       CPASSERT(ASSOCIATED(pw_pool))
     861             : 
     862      133571 :       nspins = SIZE(rho_r)
     863      133571 :       lsd = (nspins /= 1)
     864             : 
     865      133571 :       xc_fun_sections => section_vals_get_subs_vals(xc_section, "XC_FUNCTIONAL")
     866             : 
     867      133571 :       CALL xc_dset_create(deriv_set, pw_pool)
     868             : 
     869             :       CALL xc_rho_set_create(rho_set, &
     870             :                              rho_r(1)%pw_grid%bounds_local, &
     871             :                              rho_cutoff=section_get_rval(xc_section, "density_cutoff"), &
     872             :                              drho_cutoff=section_get_rval(xc_section, "gradient_cutoff"), &
     873      133571 :                              tau_cutoff=section_get_rval(xc_section, "tau_cutoff"))
     874             : 
     875             :       CALL xc_rho_set_update(rho_set, rho_r, rho_g, tau, &
     876             :                              xc_functionals_get_needs(xc_fun_sections, lsd, calc_potential), &
     877             :                              section_get_ival(xc_section, "XC_GRID%XC_DERIV"), &
     878             :                              section_get_ival(xc_section, "XC_GRID%XC_SMOOTH_RHO"), &
     879      133571 :                              pw_pool)
     880             : 
     881             :       CALL xc_functionals_eval(xc_fun_sections, &
     882             :                                lsd=lsd, &
     883             :                                rho_set=rho_set, &
     884             :                                deriv_set=deriv_set, &
     885      133571 :                                deriv_order=deriv_order)
     886             : 
     887      133571 :       CALL divide_by_norm_drho(deriv_set, rho_set, lsd)
     888             : 
     889      133571 :       CALL timestop(handle)
     890             : 
     891      133571 :    END SUBROUTINE xc_rho_set_and_dset_create
     892             : 
     893             : ! **************************************************************************************************
     894             : !> \brief smooths the cutoff on rho with a function smoothderiv_rho that is 0
     895             : !>      for rho<rho_cutoff and 1 for rho>rho_cutoff*rho_smooth_cutoff_range:
     896             : !>      E= integral e_0*smoothderiv_rho => dE/d...= de/d... * smooth,
     897             : !>      dE/drho = de/drho * smooth + e_0 * dsmooth/drho
     898             : !> \param pot the potential to smooth
     899             : !> \param rho , rhoa,rhob: the value of the density (used to apply the cutoff)
     900             : !> \param rhoa ...
     901             : !> \param rhob ...
     902             : !> \param rho_cutoff the value at whch the cutoff function must go to 0
     903             : !> \param rho_smooth_cutoff_range range of the smoothing
     904             : !> \param e_0 value of e_0, if given it is assumed that pot is the derivative
     905             : !>        wrt. to rho, and needs the dsmooth*e_0 contribution
     906             : !> \param e_0_scale_factor ...
     907             : !> \author Fawzi Mohamed
     908             : ! **************************************************************************************************
     909      254303 :    SUBROUTINE smooth_cutoff(pot, rho, rhoa, rhob, rho_cutoff, &
     910             :                             rho_smooth_cutoff_range, e_0, e_0_scale_factor)
     911             :       REAL(kind=dp), DIMENSION(:, :, :), INTENT(IN), &
     912             :          POINTER                                         :: pot, rho, rhoa, rhob
     913             :       REAL(kind=dp), INTENT(in)                          :: rho_cutoff, rho_smooth_cutoff_range
     914             :       REAL(kind=dp), DIMENSION(:, :, :), OPTIONAL, &
     915             :          POINTER                                         :: e_0
     916             :       REAL(kind=dp), INTENT(in), OPTIONAL                :: e_0_scale_factor
     917             : 
     918             :       INTEGER                                            :: i, j, k
     919             :       INTEGER, DIMENSION(2, 3)                           :: bo
     920             :       REAL(kind=dp) :: my_e_0_scale_factor, my_rho, my_rho_n, my_rho_n2, rho_smooth_cutoff, &
     921             :                        rho_smooth_cutoff_2, rho_smooth_cutoff_range_2
     922             : 
     923      254303 :       CPASSERT(ASSOCIATED(pot))
     924     1017212 :       bo(1, :) = LBOUND(pot)
     925     1017212 :       bo(2, :) = UBOUND(pot)
     926      254303 :       my_e_0_scale_factor = 1.0_dp
     927      254303 :       IF (PRESENT(e_0_scale_factor)) my_e_0_scale_factor = e_0_scale_factor
     928      254303 :       rho_smooth_cutoff = rho_cutoff*rho_smooth_cutoff_range
     929      254303 :       rho_smooth_cutoff_2 = (rho_cutoff + rho_smooth_cutoff)/2
     930      254303 :       rho_smooth_cutoff_range_2 = rho_smooth_cutoff_2 - rho_cutoff
     931             : 
     932      254303 :       IF (rho_smooth_cutoff_range > 0.0_dp) THEN
     933           2 :          IF (PRESENT(e_0)) THEN
     934           0 :             CPASSERT(ASSOCIATED(e_0))
     935           0 :             IF (ASSOCIATED(rho)) THEN
     936             : !$OMP PARALLEL DO DEFAULT(NONE) &
     937             : !$OMP             SHARED(bo,e_0,pot,rho,rho_cutoff,rho_smooth_cutoff,rho_smooth_cutoff_2, &
     938             : !$OMP                    rho_smooth_cutoff_range_2,my_e_0_scale_factor) &
     939             : !$OMP             PRIVATE(k,j,i,my_rho,my_rho_n,my_rho_n2) &
     940           0 : !$OMP             COLLAPSE(3)
     941             :                DO k = bo(1, 3), bo(2, 3)
     942             :                   DO j = bo(1, 2), bo(2, 2)
     943             :                      DO i = bo(1, 1), bo(2, 1)
     944             :                         my_rho = rho(i, j, k)
     945             :                         IF (my_rho < rho_smooth_cutoff) THEN
     946             :                            IF (my_rho < rho_cutoff) THEN
     947             :                               pot(i, j, k) = 0.0_dp
     948             :                            ELSEIF (my_rho < rho_smooth_cutoff_2) THEN
     949             :                               my_rho_n = (my_rho - rho_cutoff)/rho_smooth_cutoff_range_2
     950             :                               my_rho_n2 = my_rho_n*my_rho_n
     951             :                               pot(i, j, k) = pot(i, j, k)* &
     952             :                                              my_rho_n2*(my_rho_n - 0.5_dp*my_rho_n2) + &
     953             :                                              my_e_0_scale_factor*e_0(i, j, k)* &
     954             :                                              my_rho_n2*(3.0_dp - 2.0_dp*my_rho_n) &
     955             :                                              /rho_smooth_cutoff_range_2
     956             :                            ELSE
     957             :                               my_rho_n = 2.0_dp - (my_rho - rho_cutoff)/rho_smooth_cutoff_range_2
     958             :                               my_rho_n2 = my_rho_n*my_rho_n
     959             :                               pot(i, j, k) = pot(i, j, k)* &
     960             :                                              (1.0_dp - my_rho_n2*(my_rho_n - 0.5_dp*my_rho_n2)) &
     961             :                                              + my_e_0_scale_factor*e_0(i, j, k)* &
     962             :                                              my_rho_n2*(3.0_dp - 2.0_dp*my_rho_n) &
     963             :                                              /rho_smooth_cutoff_range_2
     964             :                            END IF
     965             :                         END IF
     966             :                      END DO
     967             :                   END DO
     968             :                END DO
     969             : !$OMP END PARALLEL DO
     970             :             ELSE
     971             : !$OMP PARALLEL DO DEFAULT(NONE) &
     972             : !$OMP             SHARED(bo,pot,e_0,rhoa,rhob,rho_cutoff,rho_smooth_cutoff,rho_smooth_cutoff_2, &
     973             : !$OMP                    rho_smooth_cutoff_range_2,my_e_0_scale_factor) &
     974             : !$OMP             PRIVATE(k,j,i,my_rho,my_rho_n,my_rho_n2) &
     975           0 : !$OMP             COLLAPSE(3)
     976             :                DO k = bo(1, 3), bo(2, 3)
     977             :                   DO j = bo(1, 2), bo(2, 2)
     978             :                      DO i = bo(1, 1), bo(2, 1)
     979             :                         my_rho = rhoa(i, j, k) + rhob(i, j, k)
     980             :                         IF (my_rho < rho_smooth_cutoff) THEN
     981             :                            IF (my_rho < rho_cutoff) THEN
     982             :                               pot(i, j, k) = 0.0_dp
     983             :                            ELSEIF (my_rho < rho_smooth_cutoff_2) THEN
     984             :                               my_rho_n = (my_rho - rho_cutoff)/rho_smooth_cutoff_range_2
     985             :                               my_rho_n2 = my_rho_n*my_rho_n
     986             :                               pot(i, j, k) = pot(i, j, k)* &
     987             :                                              my_rho_n2*(my_rho_n - 0.5_dp*my_rho_n2) + &
     988             :                                              my_e_0_scale_factor*e_0(i, j, k)* &
     989             :                                              my_rho_n2*(3.0_dp - 2.0_dp*my_rho_n) &
     990             :                                              /rho_smooth_cutoff_range_2
     991             :                            ELSE
     992             :                               my_rho_n = 2.0_dp - (my_rho - rho_cutoff)/rho_smooth_cutoff_range_2
     993             :                               my_rho_n2 = my_rho_n*my_rho_n
     994             :                               pot(i, j, k) = pot(i, j, k)* &
     995             :                                              (1.0_dp - my_rho_n2*(my_rho_n - 0.5_dp*my_rho_n2)) &
     996             :                                              + my_e_0_scale_factor*e_0(i, j, k)* &
     997             :                                              my_rho_n2*(3.0_dp - 2.0_dp*my_rho_n) &
     998             :                                              /rho_smooth_cutoff_range_2
     999             :                            END IF
    1000             :                         END IF
    1001             :                      END DO
    1002             :                   END DO
    1003             :                END DO
    1004             : !$OMP END PARALLEL DO
    1005             :             END IF
    1006             :          ELSE
    1007           2 :             IF (ASSOCIATED(rho)) THEN
    1008             : !$OMP PARALLEL DO DEFAULT(NONE) &
    1009             : !$OMP             SHARED(bo,pot,rho_cutoff,rho_smooth_cutoff,rho_smooth_cutoff_2, &
    1010             : !$OMP                    rho_smooth_cutoff_range_2,rho) &
    1011             : !$OMP             PRIVATE(k,j,i,my_rho,my_rho_n,my_rho_n2) &
    1012           2 : !$OMP             COLLAPSE(3)
    1013             :                DO k = bo(1, 3), bo(2, 3)
    1014             :                   DO j = bo(1, 2), bo(2, 2)
    1015             :                      DO i = bo(1, 1), bo(2, 1)
    1016             :                         my_rho = rho(i, j, k)
    1017             :                         IF (my_rho < rho_smooth_cutoff) THEN
    1018             :                            IF (my_rho < rho_cutoff) THEN
    1019             :                               pot(i, j, k) = 0.0_dp
    1020             :                            ELSEIF (my_rho < rho_smooth_cutoff_2) THEN
    1021             :                               my_rho_n = (my_rho - rho_cutoff)/rho_smooth_cutoff_range_2
    1022             :                               my_rho_n2 = my_rho_n*my_rho_n
    1023             :                               pot(i, j, k) = pot(i, j, k)* &
    1024             :                                              my_rho_n2*(my_rho_n - 0.5_dp*my_rho_n2)
    1025             :                            ELSE
    1026             :                               my_rho_n = 2.0_dp - (my_rho - rho_cutoff)/rho_smooth_cutoff_range_2
    1027             :                               my_rho_n2 = my_rho_n*my_rho_n
    1028             :                               pot(i, j, k) = pot(i, j, k)* &
    1029             :                                              (1.0_dp - my_rho_n2*(my_rho_n - 0.5_dp*my_rho_n2))
    1030             :                            END IF
    1031             :                         END IF
    1032             :                      END DO
    1033             :                   END DO
    1034             :                END DO
    1035             : !$OMP END PARALLEL DO
    1036             :             ELSE
    1037             : !$OMP PARALLEL DO DEFAULT(NONE) &
    1038             : !$OMP             SHARED(bo,pot,rho_cutoff,rho_smooth_cutoff,rho_smooth_cutoff_2, &
    1039             : !$OMP                    rho_smooth_cutoff_range_2,rhoa,rhob) &
    1040             : !$OMP             PRIVATE(k,j,i,my_rho,my_rho_n,my_rho_n2) &
    1041           0 : !$OMP             COLLAPSE(3)
    1042             :                DO k = bo(1, 3), bo(2, 3)
    1043             :                   DO j = bo(1, 2), bo(2, 2)
    1044             :                      DO i = bo(1, 1), bo(2, 1)
    1045             :                         my_rho = rhoa(i, j, k) + rhob(i, j, k)
    1046             :                         IF (my_rho < rho_smooth_cutoff) THEN
    1047             :                            IF (my_rho < rho_cutoff) THEN
    1048             :                               pot(i, j, k) = 0.0_dp
    1049             :                            ELSEIF (my_rho < rho_smooth_cutoff_2) THEN
    1050             :                               my_rho_n = (my_rho - rho_cutoff)/rho_smooth_cutoff_range_2
    1051             :                               my_rho_n2 = my_rho_n*my_rho_n
    1052             :                               pot(i, j, k) = pot(i, j, k)* &
    1053             :                                              my_rho_n2*(my_rho_n - 0.5_dp*my_rho_n2)
    1054             :                            ELSE
    1055             :                               my_rho_n = 2.0_dp - (my_rho - rho_cutoff)/rho_smooth_cutoff_range_2
    1056             :                               my_rho_n2 = my_rho_n*my_rho_n
    1057             :                               pot(i, j, k) = pot(i, j, k)* &
    1058             :                                              (1.0_dp - my_rho_n2*(my_rho_n - 0.5_dp*my_rho_n2))
    1059             :                            END IF
    1060             :                         END IF
    1061             :                      END DO
    1062             :                   END DO
    1063             :                END DO
    1064             : !$OMP END PARALLEL DO
    1065             :             END IF
    1066             :          END IF
    1067             :       END IF
    1068      254303 :    END SUBROUTINE smooth_cutoff
    1069             : 
    1070          64 :    SUBROUTINE calc_xc_density(pot, rho, rho_cutoff)
    1071             :       TYPE(pw_r3d_rs_type), INTENT(INOUT)                       :: pot
    1072             :       TYPE(pw_r3d_rs_type), DIMENSION(:), INTENT(INOUT)         :: rho
    1073             :       REAL(kind=dp), INTENT(in)                          :: rho_cutoff
    1074             : 
    1075             :       INTEGER                                            :: i, j, k, nspins
    1076             :       INTEGER, DIMENSION(2, 3)                           :: bo
    1077             :       REAL(kind=dp)                                      :: eps1, eps2, my_rho, my_pot
    1078             : 
    1079         256 :       bo(1, :) = LBOUND(pot%array)
    1080         256 :       bo(2, :) = UBOUND(pot%array)
    1081          64 :       nspins = SIZE(rho)
    1082             : 
    1083          64 :       eps1 = rho_cutoff*1.E-4_dp
    1084          64 :       eps2 = rho_cutoff
    1085             : 
    1086        3160 :       DO k = bo(1, 3), bo(2, 3)
    1087      161272 :          DO j = bo(1, 2), bo(2, 2)
    1088     4529376 :             DO i = bo(1, 1), bo(2, 1)
    1089     4368168 :                my_pot = pot%array(i, j, k)
    1090     4368168 :                IF (nspins == 2) THEN
    1091      339714 :                   my_rho = rho(1)%array(i, j, k) + rho(2)%array(i, j, k)
    1092             :                ELSE
    1093     4028454 :                   my_rho = rho(1)%array(i, j, k)
    1094             :                END IF
    1095     4526280 :                IF (my_rho > eps1) THEN
    1096     4139924 :                   pot%array(i, j, k) = my_pot/my_rho
    1097      228244 :                ELSE IF (my_rho < eps2) THEN
    1098      228244 :                   pot%array(i, j, k) = 0.0_dp
    1099             :                ELSE
    1100           0 :                   pot%array(i, j, k) = MIN(my_pot/my_rho, my_rho**(1._dp/3._dp))
    1101             :                END IF
    1102             :             END DO
    1103             :          END DO
    1104             :       END DO
    1105             : 
    1106          64 :    END SUBROUTINE calc_xc_density
    1107             : 
    1108             : ! **************************************************************************************************
    1109             : !> \brief Exchange and Correlation functional calculations
    1110             : !> \param vxc_rho will contain the v_xc part that depend on rho
    1111             : !>        (if one of the chosen xc functionals has it it is allocated and you
    1112             : !>        are responsible for it)
    1113             : !> \param vxc_tau will contain the kinetic tau part of v_xc
    1114             : !>        (if one of the chosen xc functionals has it it is allocated and you
    1115             : !>        are responsible for it)
    1116             : !> \param exc the xc energy
    1117             : !> \param rho_r the value of the density in the real space
    1118             : !> \param rho_g value of the density in the g space (needs to be associated
    1119             : !>        only for gradient corrections)
    1120             : !> \param tau value of the kinetic density tau on the grid (can be null,
    1121             : !>        used only with meta functionals)
    1122             : !> \param xc_section which functional to calculate, and how to do it
    1123             : !> \param pw_pool the pool for the grids
    1124             : !> \param compute_virial ...
    1125             : !> \param virial_xc ...
    1126             : !> \param exc_r the value of the xc functional in the real space
    1127             : !> \par History
    1128             : !>      JGH (13-Jun-2002): adaptation to new functionals
    1129             : !>      Fawzi (11.2002): drho_g(1:3)->drho_g
    1130             : !>      Fawzi (1.2003). lsd version
    1131             : !>      Fawzi (11.2003): version using the new xc interface
    1132             : !>      Fawzi (03.2004): fft free for smoothed density and derivs, gga lsd
    1133             : !>      Fawzi (04.2004): metafunctionals
    1134             : !>      mguidon (12.2008) : laplace functionals
    1135             : !> \author fawzi; based LDA version of JGH, based on earlier version of apsi
    1136             : !> \note
    1137             : !>      Beware: some really dirty pointer handling!
    1138             : !>      energy should be kept consistent with xc_exc_calc
    1139             : ! **************************************************************************************************
    1140      110965 :    SUBROUTINE xc_vxc_pw_create(vxc_rho, vxc_tau, exc, rho_r, rho_g, tau, xc_section, &
    1141             :                                pw_pool, compute_virial, virial_xc, exc_r)
    1142             :       TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER             :: vxc_rho, vxc_tau
    1143             :       REAL(KIND=dp), INTENT(out)                         :: exc
    1144             :       TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER               :: rho_r, tau
    1145             :       TYPE(pw_c1d_gs_type), DIMENSION(:), POINTER :: rho_g
    1146             :       TYPE(section_vals_type), POINTER                   :: xc_section
    1147             :       TYPE(pw_pool_type), POINTER                        :: pw_pool
    1148             :       LOGICAL                                            :: compute_virial
    1149             :       REAL(KIND=dp), DIMENSION(3, 3), INTENT(OUT)        :: virial_xc
    1150             :       TYPE(pw_r3d_rs_type), INTENT(INOUT), OPTIONAL            :: exc_r
    1151             : 
    1152             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'xc_vxc_pw_create'
    1153             :       INTEGER, DIMENSION(2), PARAMETER :: norm_drho_spin_name = [deriv_norm_drhoa, deriv_norm_drhob]
    1154             : 
    1155             :       INTEGER                                            :: handle, idir, ispin, jdir, &
    1156             :                                                             npoints, nspins, &
    1157             :                                                             xc_deriv_method_id, xc_rho_smooth_id, deriv_id
    1158             :       INTEGER, DIMENSION(2, 3)                           :: bo
    1159             :       LOGICAL                                            :: dealloc_pw_to_deriv, has_laplace, &
    1160             :                                                             has_tau, lsd, use_virial, has_gradient, &
    1161             :                                                             has_derivs, has_rho, dealloc_pw_to_deriv_rho
    1162             :       REAL(KIND=dp)                                      :: density_smooth_cut_range, drho_cutoff, &
    1163             :                                                             rho_cutoff
    1164      110965 :       REAL(kind=dp), DIMENSION(:, :, :), POINTER         :: deriv_data, norm_drho, norm_drho_spin, &
    1165      221930 :                                                             rho, rhoa, rhob
    1166             :       TYPE(cp_sll_xc_deriv_type), POINTER                :: pos
    1167             :       TYPE(pw_grid_type), POINTER                        :: pw_grid
    1168      776755 :       TYPE(pw_r3d_rs_type), DIMENSION(3)                      :: pw_to_deriv, pw_to_deriv_rho
    1169             :       TYPE(pw_c1d_gs_type) :: tmp_g, vxc_g
    1170             :       TYPE(pw_r3d_rs_type)                                      ::  v_drho_r, virial_pw
    1171             :       TYPE(xc_derivative_set_type)                       :: deriv_set
    1172             :       TYPE(xc_derivative_type), POINTER                  :: deriv_att
    1173             :       TYPE(xc_rho_set_type)                              :: rho_set
    1174             : 
    1175      110965 :       CALL timeset(routineN, handle)
    1176      110965 :       NULLIFY (norm_drho_spin, norm_drho, pos)
    1177             : 
    1178      110965 :       pw_grid => rho_r(1)%pw_grid
    1179             : 
    1180      110965 :       CPASSERT(ASSOCIATED(xc_section))
    1181      110965 :       CPASSERT(ASSOCIATED(pw_pool))
    1182      110965 :       CPASSERT(.NOT. ASSOCIATED(vxc_rho))
    1183      110965 :       CPASSERT(.NOT. ASSOCIATED(vxc_tau))
    1184      110965 :       nspins = SIZE(rho_r)
    1185      110965 :       lsd = (nspins /= 1)
    1186      110965 :       IF (lsd) THEN
    1187       22197 :          CPASSERT(nspins == 2)
    1188             :       END IF
    1189             : 
    1190      110965 :       use_virial = compute_virial
    1191      110965 :       virial_xc = 0.0_dp
    1192             : 
    1193     1109650 :       bo = rho_r(1)%pw_grid%bounds_local
    1194      110965 :       npoints = (bo(2, 1) - bo(1, 1) + 1)*(bo(2, 2) - bo(1, 2) + 1)*(bo(2, 3) - bo(1, 3) + 1)
    1195             : 
    1196             :       ! calculate the potential derivatives
    1197             :       CALL xc_rho_set_and_dset_create(rho_set=rho_set, deriv_set=deriv_set, &
    1198             :                                       deriv_order=1, rho_r=rho_r, rho_g=rho_g, tau=tau, &
    1199             :                                       xc_section=xc_section, &
    1200             :                                       pw_pool=pw_pool, &
    1201      110965 :                                       calc_potential=.TRUE.)
    1202             : 
    1203             :       CALL section_vals_val_get(xc_section, "XC_GRID%XC_DERIV", &
    1204      110965 :                                 i_val=xc_deriv_method_id)
    1205             :       CALL section_vals_val_get(xc_section, "XC_GRID%XC_SMOOTH_RHO", &
    1206      110965 :                                 i_val=xc_rho_smooth_id)
    1207             :       CALL section_vals_val_get(xc_section, "DENSITY_SMOOTH_CUTOFF_RANGE", &
    1208      110965 :                                 r_val=density_smooth_cut_range)
    1209             : 
    1210             :       CALL xc_rho_set_get(rho_set, rho_cutoff=rho_cutoff, &
    1211      110965 :                           drho_cutoff=drho_cutoff)
    1212             : 
    1213      110965 :       CALL check_for_derivatives(deriv_set, lsd, has_rho, has_gradient, has_tau, has_laplace)
    1214             :       ! check for unknown derivatives
    1215      110965 :       has_derivs = has_rho .OR. has_gradient .OR. has_tau .OR. has_laplace
    1216             : 
    1217      466057 :       ALLOCATE (vxc_rho(nspins))
    1218             : 
    1219             :       CALL xc_rho_set_get(rho_set, rho=rho, rhoa=rhoa, rhob=rhob, &
    1220      110965 :                           can_return_null=.TRUE.)
    1221             : 
    1222             :       ! recover the vxc arrays
    1223      110965 :       IF (lsd) THEN
    1224       22197 :          CALL xc_dset_recover_pw(deriv_set, [deriv_rhoa], vxc_rho(1), pw_grid, pw_pool)
    1225       22197 :          CALL xc_dset_recover_pw(deriv_set, [deriv_rhob], vxc_rho(2), pw_grid, pw_pool)
    1226             : 
    1227             :       ELSE
    1228       88768 :          CALL xc_dset_recover_pw(deriv_set, [deriv_rho], vxc_rho(1), pw_grid, pw_pool)
    1229             :       END IF
    1230             : 
    1231      110965 :       deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drho])
    1232      110965 :       IF (ASSOCIATED(deriv_att)) THEN
    1233       59843 :          CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
    1234             : 
    1235             :          CALL xc_rho_set_get(rho_set, norm_drho=norm_drho, &
    1236             :                              rho_cutoff=rho_cutoff, &
    1237             :                              drho_cutoff=drho_cutoff, &
    1238       59843 :                              can_return_null=.TRUE.)
    1239       59843 :          CALL xc_rho_set_recover_pw(rho_set, pw_grid, pw_pool, dealloc_pw_to_deriv_rho, drho=pw_to_deriv_rho)
    1240             : 
    1241       59843 :          CPASSERT(ASSOCIATED(deriv_data))
    1242       59843 :          IF (use_virial) THEN
    1243        1526 :             CALL pw_pool%create_pw(virial_pw)
    1244        1526 :             CALL pw_zero(virial_pw)
    1245        6104 :             DO idir = 1, 3
    1246        4578 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(virial_pw,pw_to_deriv_rho,deriv_data,idir)
    1247             :                virial_pw%array(:, :, :) = pw_to_deriv_rho(idir)%array(:, :, :)*deriv_data(:, :, :)
    1248             : !$OMP END PARALLEL WORKSHARE
    1249       15260 :                DO jdir = 1, idir
    1250             :                   virial_xc(idir, jdir) = -pw_grid%dvol* &
    1251             :                                           accurate_dot_product(virial_pw%array(:, :, :), &
    1252        9156 :                                                                pw_to_deriv_rho(jdir)%array(:, :, :))
    1253       13734 :                   virial_xc(jdir, idir) = virial_xc(idir, jdir)
    1254             :                END DO
    1255             :             END DO
    1256        1526 :             CALL pw_pool%give_back_pw(virial_pw)
    1257             :          END IF ! use_virial
    1258      239372 :          DO idir = 1, 3
    1259      179529 :             CPASSERT(ASSOCIATED(pw_to_deriv_rho(idir)%array))
    1260      239372 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(deriv_data,pw_to_deriv_rho,idir)
    1261             :             pw_to_deriv_rho(idir)%array(:, :, :) = pw_to_deriv_rho(idir)%array(:, :, :)*deriv_data(:, :, :)
    1262             : !$OMP END PARALLEL WORKSHARE
    1263             :          END DO
    1264             : 
    1265             :          ! Deallocate pw to save memory
    1266       59843 :          CALL pw_pool%give_back_cr3d(deriv_att%deriv_data)
    1267             : 
    1268             :       END IF
    1269             : 
    1270      110965 :       IF ((has_gradient .AND. xc_requires_tmp_g(xc_deriv_method_id)) .OR. pw_grid%spherical) THEN
    1271       59613 :          CALL pw_pool%create_pw(vxc_g)
    1272       59613 :          IF (.NOT. pw_grid%spherical) THEN
    1273       59613 :             CALL pw_pool%create_pw(tmp_g)
    1274             :          END IF
    1275             :       END IF
    1276             : 
    1277      244127 :       DO ispin = 1, nspins
    1278             : 
    1279      133162 :          IF (lsd) THEN
    1280       44394 :             IF (ispin == 1) THEN
    1281             :                CALL xc_rho_set_get(rho_set, norm_drhoa=norm_drho_spin, &
    1282       22197 :                                    can_return_null=.TRUE.)
    1283       22197 :                IF (ASSOCIATED(norm_drho_spin)) CALL xc_rho_set_recover_pw( &
    1284       14144 :                   rho_set, pw_grid, pw_pool, dealloc_pw_to_deriv, drhoa=pw_to_deriv)
    1285             :             ELSE
    1286             :                CALL xc_rho_set_get(rho_set, norm_drhob=norm_drho_spin, &
    1287       22197 :                                    can_return_null=.TRUE.)
    1288       22197 :                IF (ASSOCIATED(norm_drho_spin)) CALL xc_rho_set_recover_pw( &
    1289       14144 :                   rho_set, pw_grid, pw_pool, dealloc_pw_to_deriv, drhob=pw_to_deriv)
    1290             :             END IF
    1291             : 
    1292       88788 :             deriv_att => xc_dset_get_derivative(deriv_set, [norm_drho_spin_name(ispin)])
    1293       44394 :             IF (ASSOCIATED(deriv_att)) THEN
    1294             :                CPASSERT(lsd)
    1295       28288 :                CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
    1296             : 
    1297       28288 :                IF (use_virial) THEN
    1298         100 :                   CALL pw_pool%create_pw(virial_pw)
    1299         100 :                   CALL pw_zero(virial_pw)
    1300         400 :                   DO idir = 1, 3
    1301         300 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(deriv_data,pw_to_deriv,virial_pw,idir)
    1302             :                      virial_pw%array(:, :, :) = pw_to_deriv(idir)%array(:, :, :)*deriv_data(:, :, :)
    1303             : !$OMP END PARALLEL WORKSHARE
    1304        1000 :                      DO jdir = 1, idir
    1305             :                         virial_xc(idir, jdir) = virial_xc(idir, jdir) - pw_grid%dvol* &
    1306             :                                                 accurate_dot_product(virial_pw%array(:, :, :), &
    1307         600 :                                                                      pw_to_deriv(jdir)%array(:, :, :))
    1308         900 :                         virial_xc(jdir, idir) = virial_xc(idir, jdir)
    1309             :                      END DO
    1310             :                   END DO
    1311         100 :                   CALL pw_pool%give_back_pw(virial_pw)
    1312             :                END IF ! use_virial
    1313             : 
    1314      113152 :                DO idir = 1, 3
    1315      113152 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(deriv_data,idir,pw_to_deriv)
    1316             :                   pw_to_deriv(idir)%array(:, :, :) = deriv_data(:, :, :)*pw_to_deriv(idir)%array(:, :, :)
    1317             : !$OMP END PARALLEL WORKSHARE
    1318             :                END DO
    1319             :             END IF ! deriv_att
    1320             : 
    1321             :          END IF ! LSD
    1322             : 
    1323      133162 :          IF (ASSOCIATED(pw_to_deriv_rho(1)%array)) THEN
    1324       73229 :             IF (.NOT. ASSOCIATED(pw_to_deriv(1)%array)) THEN
    1325       46457 :                pw_to_deriv = pw_to_deriv_rho
    1326       46457 :                dealloc_pw_to_deriv = ((.NOT. lsd) .OR. (ispin == 2))
    1327       46457 :                dealloc_pw_to_deriv = dealloc_pw_to_deriv .AND. dealloc_pw_to_deriv_rho
    1328             :             ELSE
    1329             :                ! This branch is called in case of open-shell systems
    1330             :                ! Add the contributions from norm_drho and norm_drho_spin
    1331      107088 :                DO idir = 1, 3
    1332       80316 :                   CALL pw_axpy(pw_to_deriv_rho(idir), pw_to_deriv(idir))
    1333      107088 :                   IF (ispin == 2) THEN
    1334       40158 :                      IF (dealloc_pw_to_deriv_rho) THEN
    1335       40158 :                         CALL pw_pool%give_back_pw(pw_to_deriv_rho(idir))
    1336             :                      END IF
    1337             :                   END IF
    1338             :                END DO
    1339             :             END IF
    1340             :          END IF
    1341             : 
    1342      133162 :          IF (ASSOCIATED(pw_to_deriv(1)%array)) THEN
    1343      298980 :             DO idir = 1, 3
    1344      298980 :                CALL pw_scale(pw_to_deriv(idir), -1.0_dp)
    1345             :             END DO
    1346             : 
    1347       74745 :             CALL xc_pw_divergence(xc_deriv_method_id, pw_to_deriv, tmp_g, vxc_g, vxc_rho(ispin))
    1348             : 
    1349       74745 :             IF (dealloc_pw_to_deriv) THEN
    1350      298980 :             DO idir = 1, 3
    1351      298980 :                CALL pw_pool%give_back_pw(pw_to_deriv(idir))
    1352             :             END DO
    1353             :             END IF
    1354             :          END IF
    1355             : 
    1356             :          ! Add laplace part to vxc_rho
    1357      133162 :          IF (has_laplace) THEN
    1358        1092 :             IF (lsd) THEN
    1359         472 :                IF (ispin == 1) THEN
    1360             :                   deriv_id = deriv_laplace_rhoa
    1361             :                ELSE
    1362         236 :                   deriv_id = deriv_laplace_rhob
    1363             :                END IF
    1364             :             ELSE
    1365             :                deriv_id = deriv_laplace_rho
    1366             :             END IF
    1367             : 
    1368        2184 :             CALL xc_dset_recover_pw(deriv_set, [deriv_id], pw_to_deriv(1), pw_grid)
    1369             : 
    1370        1092 :             IF (use_virial) CALL virial_laplace(rho_r(ispin), pw_pool, virial_xc, pw_to_deriv(1)%array)
    1371             : 
    1372        1092 :             CALL xc_pw_laplace(pw_to_deriv(1), pw_pool, xc_deriv_method_id)
    1373             : 
    1374        1092 :             CALL pw_axpy(pw_to_deriv(1), vxc_rho(ispin))
    1375             : 
    1376        1092 :             CALL pw_pool%give_back_pw(pw_to_deriv(1))
    1377             :          END IF
    1378             : 
    1379      133162 :          IF (pw_grid%spherical) THEN
    1380             :             ! filter vxc
    1381           0 :             CALL pw_transfer(vxc_rho(ispin), vxc_g)
    1382           0 :             CALL pw_transfer(vxc_g, vxc_rho(ispin))
    1383             :          END IF
    1384             :          CALL smooth_cutoff(pot=vxc_rho(ispin)%array, rho=rho, rhoa=rhoa, rhob=rhob, &
    1385             :                             rho_cutoff=rho_cutoff*density_smooth_cut_range, &
    1386      133162 :                             rho_smooth_cutoff_range=density_smooth_cut_range)
    1387             : 
    1388      133162 :          v_drho_r = vxc_rho(ispin)
    1389      133162 :          CALL pw_pool%create_pw(vxc_rho(ispin))
    1390      133162 :          CALL xc_pw_smooth(v_drho_r, vxc_rho(ispin), xc_rho_smooth_id)
    1391      244127 :          CALL pw_pool%give_back_pw(v_drho_r)
    1392             :       END DO
    1393             : 
    1394      110965 :       CALL pw_pool%give_back_pw(vxc_g)
    1395      110965 :       CALL pw_pool%give_back_pw(tmp_g)
    1396             : 
    1397             :       ! 0-deriv -> value of exc
    1398             :       ! this has to be kept consistent with xc_exc_calc
    1399      110965 :       IF (has_derivs) THEN
    1400      110647 :          CALL xc_dset_recover_pw(deriv_set, [INTEGER::], v_drho_r, pw_grid)
    1401             : 
    1402             :          CALL smooth_cutoff(pot=v_drho_r%array, rho=rho, rhoa=rhoa, rhob=rhob, &
    1403             :                             rho_cutoff=rho_cutoff, &
    1404      110647 :                             rho_smooth_cutoff_range=density_smooth_cut_range)
    1405             : 
    1406      110647 :          exc = pw_integrate_function(v_drho_r)
    1407             :          !
    1408             :          ! return the xc functional value at the grid points
    1409             :          !
    1410      110647 :          IF (PRESENT(exc_r)) THEN
    1411          96 :             exc_r = v_drho_r
    1412             :          ELSE
    1413      110551 :             CALL v_drho_r%release()
    1414             :          END IF
    1415             :       ELSE
    1416         318 :          exc = 0.0_dp
    1417             :       END IF
    1418             : 
    1419      110965 :       CALL xc_rho_set_release(rho_set, pw_pool=pw_pool)
    1420             : 
    1421             :       ! tau part
    1422      110965 :       IF (has_tau) THEN
    1423        8230 :          ALLOCATE (vxc_tau(nspins))
    1424        2532 :          IF (lsd) THEN
    1425         634 :             CALL xc_dset_recover_pw(deriv_set, [deriv_tau_a], vxc_tau(1), pw_grid)
    1426         634 :             CALL xc_dset_recover_pw(deriv_set, [deriv_tau_b], vxc_tau(2), pw_grid)
    1427             :          ELSE
    1428        1898 :             CALL xc_dset_recover_pw(deriv_set, [deriv_tau], vxc_tau(1), pw_grid)
    1429             :          END IF
    1430        5698 :          DO ispin = 1, nspins
    1431        5698 :             CPASSERT(ASSOCIATED(vxc_tau(ispin)%array))
    1432             :          END DO
    1433             :       END IF
    1434      110965 :       CALL xc_dset_release(deriv_set)
    1435             : 
    1436      110965 :       CALL timestop(handle)
    1437             : 
    1438     2330265 :    END SUBROUTINE xc_vxc_pw_create
    1439             : 
    1440             : ! **************************************************************************************************
    1441             : !> \brief calculates just the exchange and correlation energy
    1442             : !>      (no vxc)
    1443             : !> \param rho_r      realspace density on the grid
    1444             : !> \param rho_g      g-space density on the grid
    1445             : !> \param tau        kinetic energy density on the grid
    1446             : !> \param xc_section XC parameters
    1447             : !> \param pw_pool    pool of plain-wave grids
    1448             : !> \return the XC energy
    1449             : !> \par History
    1450             : !>      11.2003 created [fawzi]
    1451             : !> \author fawzi
    1452             : !> \note
    1453             : !>      has to be kept consistent with xc_vxc_pw_create
    1454             : ! **************************************************************************************************
    1455       20984 :    FUNCTION xc_exc_calc(rho_r, rho_g, tau, xc_section, pw_pool) &
    1456             :       RESULT(exc)
    1457             :       TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER               :: rho_r, tau
    1458             :       TYPE(pw_c1d_gs_type), DIMENSION(:), POINTER :: rho_g
    1459             :       TYPE(section_vals_type), POINTER                   :: xc_section
    1460             :       TYPE(pw_pool_type), POINTER                        :: pw_pool
    1461             :       REAL(kind=dp)                                      :: exc
    1462             : 
    1463             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'xc_exc_calc'
    1464             : 
    1465             :       INTEGER                                            :: handle
    1466             :       REAL(dp)                                           :: density_smooth_cut_range, rho_cutoff
    1467       10492 :       REAL(dp), DIMENSION(:, :, :), POINTER              :: e_0
    1468             :       TYPE(xc_derivative_set_type)                       :: deriv_set
    1469             :       TYPE(xc_derivative_type), POINTER                  :: deriv
    1470             :       TYPE(xc_rho_set_type)                              :: rho_set
    1471             : 
    1472       10492 :       CALL timeset(routineN, handle)
    1473       10492 :       NULLIFY (deriv, e_0)
    1474       10492 :       exc = 0.0_dp
    1475             : 
    1476             :       ! this has to be consistent with what is done in xc_vxc_pw_create
    1477             :       CALL xc_rho_set_and_dset_create(rho_set=rho_set, &
    1478             :                                       deriv_set=deriv_set, deriv_order=0, &
    1479             :                                       rho_r=rho_r, rho_g=rho_g, tau=tau, xc_section=xc_section, &
    1480             :                                       pw_pool=pw_pool, &
    1481       10492 :                                       calc_potential=.FALSE.)
    1482       10492 :       deriv => xc_dset_get_derivative(deriv_set, [INTEGER::])
    1483             : 
    1484       10492 :       IF (ASSOCIATED(deriv)) THEN
    1485       10492 :          CALL xc_derivative_get(deriv, deriv_data=e_0)
    1486             : 
    1487             :          CALL section_vals_val_get(xc_section, "DENSITY_CUTOFF", &
    1488       10492 :                                    r_val=rho_cutoff)
    1489             :          CALL section_vals_val_get(xc_section, "DENSITY_SMOOTH_CUTOFF_RANGE", &
    1490       10492 :                                    r_val=density_smooth_cut_range)
    1491             :          CALL smooth_cutoff(pot=e_0, rho=rho_set%rho, &
    1492             :                             rhoa=rho_set%rhoa, rhob=rho_set%rhob, &
    1493             :                             rho_cutoff=rho_cutoff, &
    1494       10492 :                             rho_smooth_cutoff_range=density_smooth_cut_range)
    1495             : 
    1496       10492 :          exc = accurate_sum(e_0)*rho_r(1)%pw_grid%dvol
    1497       10492 :          IF (rho_r(1)%pw_grid%para%mode == PW_MODE_DISTRIBUTED) THEN
    1498       10354 :             CALL rho_r(1)%pw_grid%para%group%sum(exc)
    1499             :          END IF
    1500             : 
    1501       10492 :          CALL xc_rho_set_release(rho_set, pw_pool=pw_pool)
    1502       10492 :          CALL xc_dset_release(deriv_set)
    1503             :       END IF
    1504       10492 :       CALL timestop(handle)
    1505      199348 :    END FUNCTION xc_exc_calc
    1506             : 
    1507             : ! **************************************************************************************************
    1508             : !> \brief Caller routine to calculate the second order potential in the direction of rho1_r
    1509             : !> \param v_xc XC potential, will be allocated, to be integrated with the KS density
    1510             : !> \param v_xc_tau ...
    1511             : !> \param deriv_set XC derivatives from xc_prep_2nd_deriv
    1512             : !> \param rho_set XC rho set from KS rho from xc_prep_2nd_deriv
    1513             : !> \param rho1_r first-order density in r space
    1514             : !> \param rho1_g first-order density in g space
    1515             : !> \param tau1_r ...
    1516             : !> \param pw_pool pw pool to create new grids
    1517             : !> \param xc_section XC section to calculate the derivatives from
    1518             : !> \param gapw whether to carry out GAPW (not possible with numerical derivatives)
    1519             : !> \param vxg GAPW potential
    1520             : !> \param do_excitations ...
    1521             : !> \param do_triplet ...
    1522             : !> \param compute_virial ...
    1523             : !> \param virial_xc virial terms will be collected here
    1524             : ! **************************************************************************************************
    1525       13850 :    SUBROUTINE xc_calc_2nd_deriv(v_xc, v_xc_tau, deriv_set, rho_set, rho1_r, rho1_g, tau1_r, &
    1526             :                                 pw_pool, xc_section, gapw, vxg, &
    1527             :                                 do_excitations, do_triplet, &
    1528             :                                 compute_virial, virial_xc)
    1529             : 
    1530             :       TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER        :: v_xc, v_xc_tau
    1531             :       TYPE(xc_derivative_set_type)                       :: deriv_set
    1532             :       TYPE(xc_rho_set_type)                              :: rho_set
    1533             :       TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER        :: rho1_r, tau1_r
    1534             :       TYPE(pw_c1d_gs_type), DIMENSION(:), POINTER        :: rho1_g
    1535             :       TYPE(pw_pool_type), INTENT(IN), POINTER            :: pw_pool
    1536             :       TYPE(section_vals_type), INTENT(IN), POINTER       :: xc_section
    1537             :       LOGICAL, INTENT(IN)                                :: gapw
    1538             :       REAL(KIND=dp), DIMENSION(:, :, :, :), OPTIONAL, &
    1539             :          POINTER                                         :: vxg
    1540             :       LOGICAL, INTENT(IN), OPTIONAL                      :: do_excitations, &
    1541             :                                                             do_triplet, compute_virial
    1542             :       REAL(KIND=dp), DIMENSION(3, 3), INTENT(INOUT), &
    1543             :          OPTIONAL                                        :: virial_xc
    1544             : 
    1545             :       CHARACTER(len=*), PARAMETER :: routineN = 'xc_calc_2nd_deriv'
    1546             : 
    1547             :       INTEGER                                            :: handle, ispin, nspins
    1548             :       INTEGER, DIMENSION(2, 3)                           :: bo
    1549             :       LOGICAL                                            :: lsd, my_compute_virial, &
    1550             :                                                             my_do_excitations, &
    1551             :                                                             my_do_triplet
    1552             :       REAL(KIND=dp)                                      :: fac
    1553             :       TYPE(section_vals_type), POINTER                   :: xc_fun_section
    1554             :       TYPE(xc_rho_cflags_type)                           :: needs
    1555             :       TYPE(xc_rho_set_type)                              :: rho1_set
    1556             : 
    1557       13850 :       CALL timeset(routineN, handle)
    1558             : 
    1559       13850 :       my_compute_virial = .FALSE.
    1560       13850 :       IF (PRESENT(compute_virial)) my_compute_virial = compute_virial
    1561             : 
    1562       13850 :       my_do_excitations = .FALSE.
    1563       13850 :       IF (PRESENT(do_excitations)) my_do_excitations = do_excitations
    1564             : 
    1565       13850 :       my_do_triplet = .FALSE.
    1566       13850 :       IF (PRESENT(do_triplet)) my_do_triplet = do_triplet
    1567             : 
    1568       13850 :       nspins = SIZE(rho1_r)
    1569       13850 :       lsd = (nspins == 2)
    1570       13850 :       IF (nspins == 1 .AND. my_do_excitations .AND. my_do_triplet) THEN
    1571           0 :          nspins = 2
    1572           0 :          lsd = .TRUE.
    1573             :       END IF
    1574             : 
    1575       13850 :       NULLIFY (v_xc, v_xc_tau)
    1576       57256 :       ALLOCATE (v_xc(nspins))
    1577       29556 :       DO ispin = 1, nspins
    1578       15706 :          CALL pw_pool%create_pw(v_xc(ispin))
    1579       29556 :          CALL pw_zero(v_xc(ispin))
    1580             :       END DO
    1581             : 
    1582       13850 :       xc_fun_section => section_vals_get_subs_vals(xc_section, "XC_FUNCTIONAL")
    1583       13850 :       needs = xc_functionals_get_needs(xc_fun_section, lsd, .TRUE.)
    1584             : 
    1585       13850 :       IF (needs%tau .OR. needs%tau_spin) THEN
    1586         536 :          IF (.NOT. ASSOCIATED(tau1_r)) &
    1587           0 :             CPABORT("Tau-dependent functionals requires allocated kinetic energy density grid")
    1588        1736 :          ALLOCATE (v_xc_tau(nspins))
    1589        1200 :          DO ispin = 1, nspins
    1590         664 :             CALL pw_pool%create_pw(v_xc_tau(ispin))
    1591       14514 :             CALL pw_zero(v_xc_tau(ispin))
    1592             :          END DO
    1593             :       END IF
    1594             : 
    1595       13850 :       IF (section_get_lval(xc_section, "2ND_DERIV_ANALYTICAL")) THEN
    1596             :          !------!
    1597             :          ! rho1 !
    1598             :          !------!
    1599      135500 :          bo = rho1_r(1)%pw_grid%bounds_local
    1600             :          ! create the place where to store the argument for the functionals
    1601             :          CALL xc_rho_set_create(rho1_set, bo, &
    1602             :                                 rho_cutoff=section_get_rval(xc_section, "DENSITY_CUTOFF"), &
    1603             :                                 drho_cutoff=section_get_rval(xc_section, "GRADIENT_CUTOFF"), &
    1604       13550 :                                 tau_cutoff=section_get_rval(xc_section, "TAU_CUTOFF"))
    1605             : 
    1606             :          ! calculate the arguments needed by the functionals
    1607             :          CALL xc_rho_set_update(rho1_set, rho1_r, rho1_g, tau1_r, needs, &
    1608             :                                 section_get_ival(xc_section, "XC_GRID%XC_DERIV"), &
    1609             :                                 section_get_ival(xc_section, "XC_GRID%XC_SMOOTH_RHO"), &
    1610       13550 :                                 pw_pool)
    1611             : 
    1612       13550 :          fac = 0._dp
    1613       13550 :          IF (nspins == 1 .AND. my_do_excitations) THEN
    1614        1074 :             IF (my_do_triplet) fac = -1.0_dp
    1615             :          END IF
    1616             : 
    1617             :          CALL xc_calc_2nd_deriv_analytical(v_xc, v_xc_tau, deriv_set, rho_set, &
    1618             :                                            rho1_set, pw_pool, xc_section, gapw, vxg=vxg, &
    1619       13550 :                                            tddfpt_fac=fac, compute_virial=compute_virial, virial_xc=virial_xc)
    1620             : 
    1621       13550 :          CALL xc_rho_set_release(rho1_set)
    1622             : 
    1623             :       ELSE
    1624         300 :          IF (gapw) CPABORT("Numerical 2nd derivatives not implemented with GAPW")
    1625             : 
    1626             :          CALL xc_calc_2nd_deriv_numerical(v_xc, v_xc_tau, rho_set, rho1_r, rho1_g, tau1_r, &
    1627             :                                           pw_pool, xc_section, &
    1628             :                                           my_do_excitations .AND. my_do_triplet, &
    1629         300 :                                           compute_virial, virial_xc, deriv_set)
    1630             :       END IF
    1631             : 
    1632       13850 :       CALL timestop(handle)
    1633             : 
    1634      304700 :    END SUBROUTINE xc_calc_2nd_deriv
    1635             : 
    1636             : ! **************************************************************************************************
    1637             : !> \brief calculates 2nd derivative numerically
    1638             : !> \param v_xc potential to be calculated (has to be allocated already)
    1639             : !> \param v_tau tau-part of the potential to be calculated (has to be allocated already)
    1640             : !> \param rho_set KS density from xc_prep_2nd_deriv
    1641             : !> \param rho1_r first-order density in r-space
    1642             : !> \param rho1_g first-order density in g-space
    1643             : !> \param tau1_r first-order kinetic-energy density in r-space
    1644             : !> \param pw_pool pw pool for new grids
    1645             : !> \param xc_section XC section to calculate the derivatives from
    1646             : !> \param do_triplet ...
    1647             : !> \param calc_virial whether to calculate virial terms
    1648             : !> \param virial_xc collects stress tensor components (no metaGGAs!)
    1649             : !> \param deriv_set deriv set from xc_prep_2nd_deriv (only for virials)
    1650             : ! **************************************************************************************************
    1651         340 :    SUBROUTINE xc_calc_2nd_deriv_numerical(v_xc, v_tau, rho_set, rho1_r, rho1_g, tau1_r, &
    1652             :                                           pw_pool, xc_section, &
    1653             :                                           do_triplet, calc_virial, virial_xc, deriv_set)
    1654             : 
    1655             :       TYPE(pw_r3d_rs_type), DIMENSION(:), INTENT(IN), POINTER :: v_xc, v_tau
    1656             :       TYPE(xc_rho_set_type), INTENT(IN)                  :: rho_set
    1657             :       TYPE(pw_r3d_rs_type), DIMENSION(:), INTENT(IN), POINTER   :: rho1_r, tau1_r
    1658             :       TYPE(pw_c1d_gs_type), DIMENSION(:), INTENT(IN), POINTER :: rho1_g
    1659             :       TYPE(pw_pool_type), INTENT(IN), POINTER            :: pw_pool
    1660             :       TYPE(section_vals_type), INTENT(IN), POINTER       :: xc_section
    1661             :       LOGICAL, INTENT(IN)                                :: do_triplet
    1662             :       LOGICAL, INTENT(IN), OPTIONAL                      :: calc_virial
    1663             :       REAL(KIND=dp), DIMENSION(3, 3), INTENT(INOUT), &
    1664             :          OPTIONAL                                        :: virial_xc
    1665             :       TYPE(xc_derivative_set_type), OPTIONAL             :: deriv_set
    1666             : 
    1667             :       CHARACTER(len=*), PARAMETER :: routineN = 'xc_calc_2nd_deriv_numerical'
    1668             :       REAL(KIND=dp), DIMENSION(-4:4, 4), PARAMETER :: &
    1669             :          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, &
    1670             :                            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, &
    1671             :                             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, &
    1672             :             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])
    1673             : 
    1674             :       INTEGER                                            :: handle, idir, ispin, nspins, istep, nsteps
    1675             :       INTEGER, DIMENSION(2, 3)                           :: bo
    1676             :       LOGICAL                                            :: gradient_f, lsd, my_calc_virial, tau_f, laplace_f, rho_f
    1677             :       REAL(KIND=dp)                                      :: exc, gradient_cut, h, weight, step, rho_cutoff
    1678         340 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: dr1dr, dra1dra, drb1drb
    1679             :       REAL(KIND=dp), DIMENSION(3, 3)                     :: virial_dummy
    1680         340 :       REAL(KIND=dp), DIMENSION(:, :, :), POINTER         :: norm_drho, norm_drho2, norm_drho2a, &
    1681         340 :                                                             norm_drho2b, norm_drhoa, norm_drhob, &
    1682        1020 :                                                             rho, rho1, rho1a, rho1b, rhoa, rhob, &
    1683         680 :                                                             tau_a, tau_b, tau, tau1, tau1a, tau1b, laplace, laplace1, &
    1684         340 :                                                             laplacea, laplaceb, laplace1a, laplace1b, &
    1685         680 :                                                             laplace2, laplace2a, laplace2b, deriv_data
    1686        8160 :       TYPE(cp_3d_r_cp_type), DIMENSION(3)                :: drho, drho1, drho1a, drho1b, drhoa, drhob
    1687             :       TYPE(pw_r3d_rs_type)                                      :: v_drho, v_drhoa, v_drhob
    1688         340 :       TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER             :: vxc_rho, vxc_tau
    1689         340 :       TYPE(pw_c1d_gs_type), DIMENSION(:), POINTER :: rho_g
    1690         340 :       TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER               ::  rho_r, tau_r
    1691             :       TYPE(pw_r3d_rs_type)                                      :: virial_pw, v_laplace, v_laplacea, v_laplaceb
    1692             :       TYPE(section_vals_type), POINTER                   :: xc_fun_section
    1693             :       TYPE(xc_derivative_set_type)                       :: deriv_set1
    1694             :       TYPE(xc_rho_cflags_type)                           :: needs
    1695             :       TYPE(xc_rho_set_type)                              :: rho1_set, rho2_set
    1696             : 
    1697         340 :       CALL timeset(routineN, handle)
    1698             : 
    1699         340 :       my_calc_virial = .FALSE.
    1700         340 :       IF (PRESENT(calc_virial) .AND. PRESENT(virial_xc)) my_calc_virial = calc_virial
    1701             : 
    1702         340 :       nspins = SIZE(v_xc)
    1703             : 
    1704         340 :       NULLIFY (tau, tau_r, tau_a, tau_b)
    1705             : 
    1706         340 :       h = section_get_rval(xc_section, "STEP_SIZE")
    1707         340 :       nsteps = section_get_ival(xc_section, "NSTEPS")
    1708         340 :       IF (nsteps < LBOUND(weights, 2) .OR. nspins > UBOUND(weights, 2)) THEN
    1709           0 :          CPABORT("The number of steps must be a value from 1 to 4.")
    1710             :       END IF
    1711             : 
    1712         340 :       IF (nspins == 2) THEN
    1713         148 :          NULLIFY (vxc_rho, rho_g, vxc_tau)
    1714         444 :          ALLOCATE (rho_r(2))
    1715         444 :          DO ispin = 1, nspins
    1716         444 :             CALL pw_pool%create_pw(rho_r(ispin))
    1717             :          END DO
    1718         148 :          IF (ASSOCIATED(tau1_r) .AND. ASSOCIATED(v_tau)) THEN
    1719         162 :             ALLOCATE (tau_r(2))
    1720         162 :             DO ispin = 1, nspins
    1721         162 :                CALL pw_pool%create_pw(tau_r(ispin))
    1722             :             END DO
    1723             :          END IF
    1724         148 :          CALL xc_rho_set_get(rho_set, can_return_null=.TRUE., rhoa=rhoa, rhob=rhob, tau_a=tau_a, tau_b=tau_b)
    1725        1088 :          DO istep = -nsteps, nsteps
    1726         940 :             IF (istep == 0) CYCLE
    1727         792 :             weight = weights(istep, nsteps)/h
    1728         792 :             step = REAL(istep, dp)*h
    1729             :             CALL calc_resp_potential_numer_ab(rho_r, rho_g, rho1_r, rhoa, rhob, vxc_rho, &
    1730         792 :                                               tau_r, tau1_r, tau_a, tau_b, vxc_tau, xc_section, pw_pool, step)
    1731        2376 :             DO ispin = 1, nspins
    1732        1584 :                CALL pw_axpy(vxc_rho(ispin), v_xc(ispin), weight)
    1733        2376 :                IF (ASSOCIATED(vxc_tau) .AND. ASSOCIATED(v_tau)) THEN
    1734         456 :                   CALL pw_axpy(vxc_tau(ispin), v_tau(ispin), weight)
    1735             :                END IF
    1736             :             END DO
    1737        2376 :             DO ispin = 1, nspins
    1738        2376 :                CALL vxc_rho(ispin)%release()
    1739             :             END DO
    1740         792 :             DEALLOCATE (vxc_rho)
    1741         940 :             IF (ASSOCIATED(vxc_tau)) THEN
    1742         684 :                DO ispin = 1, nspins
    1743         684 :                   CALL vxc_tau(ispin)%release()
    1744             :                END DO
    1745         228 :                DEALLOCATE (vxc_tau)
    1746             :             END IF
    1747             :          END DO
    1748         192 :       ELSE IF (nspins == 1 .AND. do_triplet) THEN
    1749          20 :          NULLIFY (vxc_rho, vxc_tau, rho_g)
    1750          60 :          ALLOCATE (rho_r(2))
    1751          60 :          DO ispin = 1, 2
    1752          60 :             CALL pw_pool%create_pw(rho_r(ispin))
    1753             :          END DO
    1754          20 :          IF (ASSOCIATED(tau1_r) .AND. ASSOCIATED(v_tau)) THEN
    1755           0 :             ALLOCATE (tau_r(2))
    1756           0 :             DO ispin = 1, nspins
    1757           0 :                CALL pw_pool%create_pw(tau_r(ispin))
    1758             :             END DO
    1759             :          END IF
    1760          20 :          CALL xc_rho_set_get(rho_set, can_return_null=.TRUE., rhoa=rhoa, rhob=rhob, tau_a=tau_a, tau_b=tau_b)
    1761         160 :          DO istep = -nsteps, nsteps
    1762         140 :             IF (istep == 0) CYCLE
    1763         120 :             weight = weights(istep, nsteps)/h
    1764         120 :             step = REAL(istep, dp)*h
    1765             :             ! K(alpha,alpha)
    1766         120 : !$OMP PARALLEL DEFAULT(NONE) SHARED(rho_r,rhoa,rhob,step,rho1_r,tau_r,tau_a,tau_b,tau1_r)
    1767             : !$OMP WORKSHARE
    1768             :             rho_r(1)%array(:, :, :) = rhoa(:, :, :) + step*rho1_r(1)%array(:, :, :)
    1769             : !$OMP END WORKSHARE NOWAIT
    1770             : !$OMP WORKSHARE
    1771             :             rho_r(2)%array(:, :, :) = rhob(:, :, :)
    1772             : !$OMP END WORKSHARE NOWAIT
    1773             :             IF (ASSOCIATED(tau1_r)) THEN
    1774             : !$OMP WORKSHARE
    1775             :                tau_r(1)%array(:, :, :) = tau_a(:, :, :) + step*tau1_r(1)%array(:, :, :)
    1776             : !$OMP END WORKSHARE NOWAIT
    1777             : !$OMP WORKSHARE
    1778             :                tau_r(2)%array(:, :, :) = tau_b(:, :, :)
    1779             : !$OMP END WORKSHARE NOWAIT
    1780             :             END IF
    1781             : !$OMP END PARALLEL
    1782             :             CALL xc_vxc_pw_create(vxc_rho, vxc_tau, exc, rho_r, rho_g, tau_r, xc_section, &
    1783         120 :                                   pw_pool, .FALSE., virial_dummy)
    1784         120 :             CALL pw_axpy(vxc_rho(1), v_xc(1), weight)
    1785         120 :             IF (ASSOCIATED(vxc_tau) .AND. ASSOCIATED(v_tau)) THEN
    1786           0 :                CALL pw_axpy(vxc_tau(1), v_tau(1), weight)
    1787             :             END IF
    1788         360 :             DO ispin = 1, 2
    1789         360 :                CALL vxc_rho(ispin)%release()
    1790             :             END DO
    1791         120 :             DEALLOCATE (vxc_rho)
    1792         120 :             IF (ASSOCIATED(vxc_tau)) THEN
    1793           0 :             DO ispin = 1, 2
    1794           0 :                CALL vxc_tau(ispin)%release()
    1795             :             END DO
    1796           0 :             DEALLOCATE (vxc_tau)
    1797             :             END IF
    1798         120 : !$OMP PARALLEL DEFAULT(NONE) SHARED(rho_r,rhoa,rhob,step,rho1_r,tau_r,tau_a,tau_b,tau1_r)
    1799             : !$OMP WORKSHARE
    1800             :             ! K(alpha,beta)
    1801             :             rho_r(1)%array(:, :, :) = rhoa(:, :, :)
    1802             : !$OMP END WORKSHARE NOWAIT
    1803             : !$OMP WORKSHARE
    1804             :             rho_r(2)%array(:, :, :) = rhob(:, :, :) + step*rho1_r(1)%array(:, :, :)
    1805             : !$OMP END WORKSHARE NOWAIT
    1806             :             IF (ASSOCIATED(tau1_r)) THEN
    1807             : !$OMP WORKSHARE
    1808             :                tau_r(1)%array(:, :, :) = tau_a(:, :, :)
    1809             : !$OMP END WORKSHARE NOWAIT
    1810             : !$OMP WORKSHARE
    1811             :                tau_r(2)%array(:, :, :) = tau_b(:, :, :) + step*tau1_r(1)%array(:, :, :)
    1812             : !$OMP END WORKSHARE NOWAIT
    1813             :             END IF
    1814             : !$OMP END PARALLEL
    1815             :             CALL xc_vxc_pw_create(vxc_rho, vxc_tau, exc, rho_r, rho_g, tau_r, xc_section, &
    1816         120 :                                   pw_pool, .FALSE., virial_dummy)
    1817         120 :             CALL pw_axpy(vxc_rho(1), v_xc(1), weight)
    1818         120 :             IF (ASSOCIATED(vxc_tau) .AND. ASSOCIATED(v_tau)) THEN
    1819           0 :                CALL pw_axpy(vxc_tau(1), v_tau(1), weight)
    1820             :             END IF
    1821         360 :             DO ispin = 1, 2
    1822         360 :                CALL vxc_rho(ispin)%release()
    1823             :             END DO
    1824         120 :             DEALLOCATE (vxc_rho)
    1825         140 :             IF (ASSOCIATED(vxc_tau)) THEN
    1826           0 :             DO ispin = 1, 2
    1827           0 :                CALL vxc_tau(ispin)%release()
    1828             :             END DO
    1829           0 :             DEALLOCATE (vxc_tau)
    1830             :             END IF
    1831             :          END DO
    1832             :       ELSE
    1833         172 :          NULLIFY (vxc_rho, rho_r, rho_g, vxc_tau, tau_r, tau)
    1834         344 :          ALLOCATE (rho_r(1))
    1835         172 :          CALL pw_pool%create_pw(rho_r(1))
    1836         172 :          IF (ASSOCIATED(tau1_r) .AND. ASSOCIATED(v_tau)) THEN
    1837          92 :             ALLOCATE (tau_r(1))
    1838          46 :             CALL pw_pool%create_pw(tau_r(1))
    1839             :          END IF
    1840         172 :          CALL xc_rho_set_get(rho_set, can_return_null=.TRUE., rho=rho, tau=tau)
    1841        1280 :          DO istep = -nsteps, nsteps
    1842        1108 :             IF (istep == 0) CYCLE
    1843         936 :             weight = weights(istep, nsteps)/h
    1844         936 :             step = REAL(istep, dp)*h
    1845         936 : !$OMP PARALLEL DEFAULT(NONE) SHARED(rho_r,rho,step,rho1_r,tau1_r,tau,tau_r)
    1846             : !$OMP WORKSHARE
    1847             :             rho_r(1)%array(:, :, :) = rho(:, :, :) + step*rho1_r(1)%array(:, :, :)
    1848             : !$OMP END WORKSHARE NOWAIT
    1849             :             IF (ASSOCIATED(tau1_r) .AND. ASSOCIATED(tau) .AND. ASSOCIATED(tau1_r)) THEN
    1850             : !$OMP WORKSHARE
    1851             :                tau_r(1)%array(:, :, :) = tau(:, :, :) + step*tau1_r(1)%array(:, :, :)
    1852             : !$OMP END WORKSHARE NOWAIT
    1853             :             END IF
    1854             : !$OMP END PARALLEL
    1855             :             CALL xc_vxc_pw_create(vxc_rho, vxc_tau, exc, rho_r, rho_g, tau_r, xc_section, &
    1856         936 :                                   pw_pool, .FALSE., virial_dummy)
    1857         936 :             CALL pw_axpy(vxc_rho(1), v_xc(1), weight)
    1858         936 :             IF (ASSOCIATED(vxc_tau) .AND. ASSOCIATED(v_tau)) THEN
    1859         276 :                CALL pw_axpy(vxc_tau(1), v_tau(1), weight)
    1860             :             END IF
    1861         936 :             CALL vxc_rho(1)%release()
    1862         936 :             DEALLOCATE (vxc_rho)
    1863        1108 :             IF (ASSOCIATED(vxc_tau)) THEN
    1864         276 :                CALL vxc_tau(1)%release()
    1865         276 :                DEALLOCATE (vxc_tau)
    1866             :             END IF
    1867             :          END DO
    1868             :       END IF
    1869             : 
    1870         340 :       IF (my_calc_virial) THEN
    1871          36 :          lsd = (nspins == 2)
    1872          36 :          IF (nspins == 1 .AND. do_triplet) THEN
    1873           0 :             lsd = .TRUE.
    1874             :          END IF
    1875             : 
    1876          36 :          CALL check_for_derivatives(deriv_set, (nspins == 2), rho_f, gradient_f, tau_f, laplace_f)
    1877             : 
    1878             :          ! Calculate the virial terms
    1879             :          ! Those arising from the first derivatives are treated like in xc_calc_2nd_deriv_analytical
    1880             :          ! Those arising from the second derivatives are calculated numerically
    1881             :          ! We assume that all metaGGA functionals require the gradient
    1882          36 :          IF (gradient_f) THEN
    1883         360 :             bo = rho_set%local_bounds
    1884             : 
    1885             :             ! Create the work grid for the virial terms
    1886          36 :             CALL allocate_pw(virial_pw, pw_pool, bo)
    1887             : 
    1888          36 :             gradient_cut = section_get_rval(xc_section, "GRADIENT_CUTOFF")
    1889             : 
    1890             :             ! create the container to store the argument of the functionals
    1891             :             CALL xc_rho_set_create(rho1_set, bo, &
    1892             :                                    rho_cutoff=section_get_rval(xc_section, "DENSITY_CUTOFF"), &
    1893             :                                    drho_cutoff=gradient_cut, &
    1894          36 :                                    tau_cutoff=section_get_rval(xc_section, "TAU_CUTOFF"))
    1895             : 
    1896          36 :             xc_fun_section => section_vals_get_subs_vals(xc_section, "XC_FUNCTIONAL")
    1897          36 :             needs = xc_functionals_get_needs(xc_fun_section, lsd, .TRUE.)
    1898             : 
    1899             :             ! calculate the arguments needed by the functionals
    1900             :             CALL xc_rho_set_update(rho1_set, rho1_r, rho1_g, tau1_r, needs, &
    1901             :                                    section_get_ival(xc_section, "XC_GRID%XC_DERIV"), &
    1902             :                                    section_get_ival(xc_section, "XC_GRID%XC_SMOOTH_RHO"), &
    1903          36 :                                    pw_pool)
    1904             : 
    1905          36 :             IF (lsd) THEN
    1906             :                CALL xc_rho_set_get(rho_set, drhoa=drhoa, drhob=drhob, norm_drho=norm_drho, &
    1907             :                                    norm_drhoa=norm_drhoa, norm_drhob=norm_drhob, tau_a=tau_a, tau_b=tau_b, &
    1908          10 :                                    laplace_rhoa=laplacea, laplace_rhob=laplaceb, can_return_null=.TRUE.)
    1909             :                CALL xc_rho_set_get(rho1_set, rhoa=rho1a, rhob=rho1b, drhoa=drho1a, drhob=drho1b, laplace_rhoa=laplace1a, &
    1910          10 :                                    laplace_rhob=laplace1b, can_return_null=.TRUE.)
    1911             : 
    1912          10 :                CALL calc_drho_from_ab(drho, drhoa, drhob)
    1913          10 :                CALL calc_drho_from_ab(drho1, drho1a, drho1b)
    1914             :             ELSE
    1915          26 :                CALL xc_rho_set_get(rho_set, drho=drho, norm_drho=norm_drho, tau=tau, laplace_rho=laplace, can_return_null=.TRUE.)
    1916          26 :                CALL xc_rho_set_get(rho1_set, rho=rho1, drho=drho1, laplace_rho=laplace1, can_return_null=.TRUE.)
    1917             :             END IF
    1918             : 
    1919          36 :             CALL prepare_dr1dr(dr1dr, drho, drho1)
    1920             : 
    1921          36 :             IF (lsd) THEN
    1922          10 :                CALL prepare_dr1dr(dra1dra, drhoa, drho1a)
    1923          10 :                CALL prepare_dr1dr(drb1drb, drhob, drho1b)
    1924             : 
    1925          10 :                CALL allocate_pw(v_drho, pw_pool, bo)
    1926          10 :                CALL allocate_pw(v_drhoa, pw_pool, bo)
    1927          10 :                CALL allocate_pw(v_drhob, pw_pool, bo)
    1928             : 
    1929          10 :                IF (ASSOCIATED(norm_drhoa)) CALL apply_drho(deriv_set, [deriv_norm_drhoa], virial_pw, drhoa, drho1a, virial_xc, &
    1930          10 :                                                            norm_drhoa, gradient_cut, dra1dra, v_drhoa%array)
    1931          10 :                IF (ASSOCIATED(norm_drhob)) CALL apply_drho(deriv_set, [deriv_norm_drhob], virial_pw, drhob, drho1b, virial_xc, &
    1932          10 :                                                            norm_drhob, gradient_cut, drb1drb, v_drhob%array)
    1933          10 :                IF (ASSOCIATED(norm_drho)) CALL apply_drho(deriv_set, [deriv_norm_drho], virial_pw, drho, drho1, virial_xc, &
    1934           6 :                                                           norm_drho, gradient_cut, dr1dr, v_drho%array)
    1935          10 :                IF (laplace_f) THEN
    1936           2 :                   CALL xc_derivative_get(xc_dset_get_derivative(deriv_set, [deriv_laplace_rhoa]), deriv_data=deriv_data)
    1937           2 :                   CPASSERT(ASSOCIATED(deriv_data))
    1938       15026 :                   virial_pw%array(:, :, :) = -rho1a(:, :, :)
    1939           2 :                   CALL virial_laplace(virial_pw, pw_pool, virial_xc, deriv_data)
    1940             : 
    1941           2 :                   CALL allocate_pw(v_laplacea, pw_pool, bo)
    1942             : 
    1943           2 :                   CALL xc_derivative_get(xc_dset_get_derivative(deriv_set, [deriv_laplace_rhob]), deriv_data=deriv_data)
    1944           2 :                   CPASSERT(ASSOCIATED(deriv_data))
    1945       15026 :                   virial_pw%array(:, :, :) = -rho1b(:, :, :)
    1946           2 :                   CALL virial_laplace(virial_pw, pw_pool, virial_xc, deriv_data)
    1947             : 
    1948           2 :                   CALL allocate_pw(v_laplaceb, pw_pool, bo)
    1949             :                END IF
    1950             : 
    1951             :             ELSE
    1952             : 
    1953             :                ! Create the work grid for the potential of the gradient part
    1954          26 :                CALL allocate_pw(v_drho, pw_pool, bo)
    1955             : 
    1956             :                CALL apply_drho(deriv_set, [deriv_norm_drho], virial_pw, drho, drho1, virial_xc, &
    1957          26 :                                norm_drho, gradient_cut, dr1dr, v_drho%array)
    1958          26 :                IF (laplace_f) THEN
    1959           2 :                   CALL xc_derivative_get(xc_dset_get_derivative(deriv_set, [deriv_laplace_rho]), deriv_data=deriv_data)
    1960           2 :                   CPASSERT(ASSOCIATED(deriv_data))
    1961       28862 :                   virial_pw%array(:, :, :) = -rho1(:, :, :)
    1962           2 :                   CALL virial_laplace(virial_pw, pw_pool, virial_xc, deriv_data)
    1963             : 
    1964           2 :                   CALL allocate_pw(v_laplace, pw_pool, bo)
    1965             :                END IF
    1966             : 
    1967             :             END IF
    1968             : 
    1969          36 :             IF (lsd) THEN
    1970      150260 :                rho_r(1)%array = rhoa
    1971      150260 :                rho_r(2)%array = rhob
    1972             :             ELSE
    1973      701552 :                rho_r(1)%array = rho
    1974             :             END IF
    1975          36 :             IF (ASSOCIATED(tau1_r)) THEN
    1976           8 :             IF (lsd) THEN
    1977       60104 :                tau_r(1)%array = tau_a
    1978       60104 :                tau_r(2)%array = tau_b
    1979             :             ELSE
    1980      115448 :                tau_r(1)%array = tau
    1981             :             END IF
    1982             :             END IF
    1983             : 
    1984             :             ! Create deriv sets with same densities but different gradients
    1985          36 :             CALL xc_dset_create(deriv_set1, pw_pool)
    1986             : 
    1987          36 :             rho_cutoff = section_get_rval(xc_section, "DENSITY_CUTOFF")
    1988             : 
    1989             :             ! create the place where to store the argument for the functionals
    1990             :             CALL xc_rho_set_create(rho2_set, bo, &
    1991             :                                    rho_cutoff=rho_cutoff, &
    1992             :                                    drho_cutoff=section_get_rval(xc_section, "GRADIENT_CUTOFF"), &
    1993          36 :                                    tau_cutoff=section_get_rval(xc_section, "TAU_CUTOFF"))
    1994             : 
    1995             :             ! calculate the arguments needed by the functionals
    1996             :             CALL xc_rho_set_update(rho2_set, rho_r, rho_g, tau_r, needs, &
    1997             :                                    section_get_ival(xc_section, "XC_GRID%XC_DERIV"), &
    1998             :                                    section_get_ival(xc_section, "XC_GRID%XC_SMOOTH_RHO"), &
    1999          36 :                                    pw_pool)
    2000             : 
    2001          36 :             IF (lsd) THEN
    2002             :                CALL xc_rho_set_get(rho1_set, rhoa=rho1a, rhob=rho1b, tau_a=tau1a, tau_b=tau1b, &
    2003          10 :                                    laplace_rhoa=laplace1a, laplace_rhob=laplace1b, can_return_null=.TRUE.)
    2004             :                CALL xc_rho_set_get(rho2_set, norm_drhoa=norm_drho2a, norm_drhob=norm_drho2b, &
    2005          10 :                                    norm_drho=norm_drho2, laplace_rhoa=laplace2a, laplace_rhob=laplace2b, can_return_null=.TRUE.)
    2006             : 
    2007          64 :                DO istep = -nsteps, nsteps
    2008          54 :                   IF (istep == 0) CYCLE
    2009          44 :                   weight = weights(istep, nsteps)/h
    2010          44 :                   step = REAL(istep, dp)*h
    2011          44 :                   IF (ASSOCIATED(norm_drhoa)) THEN
    2012          44 :                      CALL get_derivs_rho(norm_drho2a, norm_drhoa, step, xc_fun_section, lsd, rho2_set, deriv_set1)
    2013             :                      CALL update_deriv_rho(deriv_set1, [deriv_rhoa], bo, &
    2014          44 :                                            norm_drhoa, gradient_cut, weight, rho1a, v_drhoa%array)
    2015             :                      CALL update_deriv_rho(deriv_set1, [deriv_rhob], bo, &
    2016          44 :                                            norm_drhoa, gradient_cut, weight, rho1b, v_drhoa%array)
    2017             :                      CALL update_deriv_rho(deriv_set1, [deriv_norm_drhoa], bo, &
    2018          44 :                                            norm_drhoa, gradient_cut, weight, dra1dra, v_drhoa%array)
    2019             :                      CALL update_deriv_drho_ab(deriv_set1, [deriv_norm_drhob], bo, &
    2020          44 :                                                norm_drhoa, gradient_cut, weight, dra1dra, drb1drb, v_drhoa%array, v_drhob%array)
    2021             :                      CALL update_deriv_drho_ab(deriv_set1, [deriv_norm_drho], bo, &
    2022          44 :                                                norm_drhoa, gradient_cut, weight, dra1dra, dr1dr, v_drhoa%array, v_drho%array)
    2023          44 :                      IF (tau_f) THEN
    2024             :                         CALL update_deriv_rho(deriv_set1, [deriv_tau_a], bo, &
    2025           8 :                                               norm_drhoa, gradient_cut, weight, tau1a, v_drhoa%array)
    2026             :                         CALL update_deriv_rho(deriv_set1, [deriv_tau_b], bo, &
    2027           8 :                                               norm_drhoa, gradient_cut, weight, tau1b, v_drhoa%array)
    2028             :                      END IF
    2029          44 :                      IF (laplace_f) THEN
    2030             :                         CALL update_deriv_rho(deriv_set1, [deriv_laplace_rhoa], bo, &
    2031           4 :                                               norm_drhoa, gradient_cut, weight, laplace1a, v_drhoa%array)
    2032             :                         CALL update_deriv_rho(deriv_set1, [deriv_laplace_rhob], bo, &
    2033           4 :                                               norm_drhoa, gradient_cut, weight, laplace1b, v_drhoa%array)
    2034             :                      END IF
    2035             :                   END IF
    2036             : 
    2037          44 :                   IF (ASSOCIATED(norm_drhob)) THEN
    2038          44 :                      CALL get_derivs_rho(norm_drho2b, norm_drhob, step, xc_fun_section, lsd, rho2_set, deriv_set1)
    2039             :                      CALL update_deriv_rho(deriv_set1, [deriv_rhoa], bo, &
    2040          44 :                                            norm_drhob, gradient_cut, weight, rho1a, v_drhob%array)
    2041             :                      CALL update_deriv_rho(deriv_set1, [deriv_rhob], bo, &
    2042          44 :                                            norm_drhob, gradient_cut, weight, rho1b, v_drhob%array)
    2043             :                      CALL update_deriv_rho(deriv_set1, [deriv_norm_drhob], bo, &
    2044          44 :                                            norm_drhob, gradient_cut, weight, drb1drb, v_drhob%array)
    2045             :                      CALL update_deriv_drho_ab(deriv_set1, [deriv_norm_drhoa], bo, &
    2046          44 :                                                norm_drhob, gradient_cut, weight, drb1drb, dra1dra, v_drhob%array, v_drhoa%array)
    2047             :                      CALL update_deriv_drho_ab(deriv_set1, [deriv_norm_drho], bo, &
    2048          44 :                                                norm_drhob, gradient_cut, weight, drb1drb, dr1dr, v_drhob%array, v_drho%array)
    2049          44 :                      IF (tau_f) THEN
    2050             :                         CALL update_deriv_rho(deriv_set1, [deriv_tau_a], bo, &
    2051           8 :                                               norm_drhob, gradient_cut, weight, tau1a, v_drhob%array)
    2052             :                         CALL update_deriv_rho(deriv_set1, [deriv_tau_b], bo, &
    2053           8 :                                               norm_drhob, gradient_cut, weight, tau1b, v_drhob%array)
    2054             :                      END IF
    2055          44 :                      IF (laplace_f) THEN
    2056             :                         CALL update_deriv_rho(deriv_set1, [deriv_laplace_rhoa], bo, &
    2057           4 :                                               norm_drhob, gradient_cut, weight, laplace1a, v_drhob%array)
    2058             :                         CALL update_deriv_rho(deriv_set1, [deriv_laplace_rhob], bo, &
    2059           4 :                                               norm_drhob, gradient_cut, weight, laplace1b, v_drhob%array)
    2060             :                      END IF
    2061             :                   END IF
    2062             : 
    2063          44 :                   IF (ASSOCIATED(norm_drho)) THEN
    2064          20 :                      CALL get_derivs_rho(norm_drho2, norm_drho, step, xc_fun_section, lsd, rho2_set, deriv_set1)
    2065             :                      CALL update_deriv_rho(deriv_set1, [deriv_rhoa], bo, &
    2066          20 :                                            norm_drho, gradient_cut, weight, rho1a, v_drho%array)
    2067             :                      CALL update_deriv_rho(deriv_set1, [deriv_rhob], bo, &
    2068          20 :                                            norm_drho, gradient_cut, weight, rho1b, v_drho%array)
    2069             :                      CALL update_deriv_rho(deriv_set1, [deriv_norm_drho], bo, &
    2070          20 :                                            norm_drho, gradient_cut, weight, dr1dr, v_drho%array)
    2071             :                      CALL update_deriv_drho_ab(deriv_set1, [deriv_norm_drhoa], bo, &
    2072          20 :                                                norm_drho, gradient_cut, weight, dr1dr, dra1dra, v_drho%array, v_drhoa%array)
    2073             :                      CALL update_deriv_drho_ab(deriv_set1, [deriv_norm_drhob], bo, &
    2074          20 :                                                norm_drho, gradient_cut, weight, dr1dr, drb1drb, v_drho%array, v_drhob%array)
    2075          20 :                      IF (tau_f) THEN
    2076             :                         CALL update_deriv_rho(deriv_set1, [deriv_tau_a], bo, &
    2077           8 :                                               norm_drho, gradient_cut, weight, tau1a, v_drho%array)
    2078             :                         CALL update_deriv_rho(deriv_set1, [deriv_tau_b], bo, &
    2079           8 :                                               norm_drho, gradient_cut, weight, tau1b, v_drho%array)
    2080             :                      END IF
    2081          20 :                      IF (laplace_f) THEN
    2082             :                         CALL update_deriv_rho(deriv_set1, [deriv_laplace_rhoa], bo, &
    2083           4 :                                               norm_drho, gradient_cut, weight, laplace1a, v_drho%array)
    2084             :                         CALL update_deriv_rho(deriv_set1, [deriv_laplace_rhob], bo, &
    2085           4 :                                               norm_drho, gradient_cut, weight, laplace1b, v_drho%array)
    2086             :                      END IF
    2087             :                   END IF
    2088             : 
    2089          54 :                   IF (laplace_f) THEN
    2090             : 
    2091           4 :                      CALL get_derivs_rho(laplace2a, laplacea, step, xc_fun_section, lsd, rho2_set, deriv_set1)
    2092             : 
    2093             :                      ! Obtain the numerical 2nd derivatives w.r.t. to drho and collect the potential
    2094             :                      CALL update_deriv(deriv_set1, laplacea, rho_cutoff, [deriv_rhoa], bo, &
    2095           4 :                                        weight, rho1a, v_laplacea%array)
    2096             :                      CALL update_deriv(deriv_set1, laplacea, rho_cutoff, [deriv_rhob], bo, &
    2097           4 :                                        weight, rho1b, v_laplacea%array)
    2098           4 :                      IF (ASSOCIATED(norm_drho)) THEN
    2099             :                         CALL update_deriv(deriv_set1, laplacea, rho_cutoff, [deriv_norm_drho], bo, &
    2100           4 :                                           weight, dr1dr, v_laplacea%array)
    2101             :                      END IF
    2102           4 :                      IF (ASSOCIATED(norm_drhoa)) THEN
    2103             :                         CALL update_deriv(deriv_set1, laplacea, rho_cutoff, [deriv_norm_drhoa], bo, &
    2104           4 :                                           weight, dra1dra, v_laplacea%array)
    2105             :                      END IF
    2106           4 :                      IF (ASSOCIATED(norm_drhob)) THEN
    2107             :                         CALL update_deriv(deriv_set1, laplacea, rho_cutoff, [deriv_norm_drhob], bo, &
    2108           4 :                                           weight, drb1drb, v_laplacea%array)
    2109             :                      END IF
    2110             : 
    2111           4 :                      IF (ASSOCIATED(tau1a)) THEN
    2112             :                         CALL update_deriv(deriv_set1, laplacea, rho_cutoff, [deriv_tau_a], bo, &
    2113           4 :                                           weight, tau1a, v_laplacea%array)
    2114             :                      END IF
    2115           4 :                      IF (ASSOCIATED(tau1b)) THEN
    2116             :                         CALL update_deriv(deriv_set1, laplacea, rho_cutoff, [deriv_tau_b], bo, &
    2117           4 :                                           weight, tau1b, v_laplacea%array)
    2118             :                      END IF
    2119             : 
    2120             :                      CALL update_deriv(deriv_set1, laplacea, rho_cutoff, [deriv_laplace_rhoa], bo, &
    2121           4 :                                        weight, laplace1a, v_laplacea%array)
    2122             : 
    2123             :                      CALL update_deriv(deriv_set1, laplacea, rho_cutoff, [deriv_laplace_rhob], bo, &
    2124           4 :                                        weight, laplace1b, v_laplacea%array)
    2125             : 
    2126             :                      ! The same for the beta spin
    2127           4 :                      CALL get_derivs_rho(laplace2b, laplaceb, step, xc_fun_section, lsd, rho2_set, deriv_set1)
    2128             : 
    2129             :                      ! Obtain the numerical 2nd derivatives w.r.t. to drho and collect the potential
    2130             :                      CALL update_deriv(deriv_set1, laplaceb, rho_cutoff, [deriv_rhoa], bo, &
    2131           4 :                                        weight, rho1a, v_laplaceb%array)
    2132             :                      CALL update_deriv(deriv_set1, laplaceb, rho_cutoff, [deriv_rhob], bo, &
    2133           4 :                                        weight, rho1b, v_laplaceb%array)
    2134           4 :                      IF (ASSOCIATED(norm_drho)) THEN
    2135             :                         CALL update_deriv(deriv_set1, laplaceb, rho_cutoff, [deriv_norm_drho], bo, &
    2136           4 :                                           weight, dr1dr, v_laplaceb%array)
    2137             :                      END IF
    2138           4 :                      IF (ASSOCIATED(norm_drhoa)) THEN
    2139             :                         CALL update_deriv(deriv_set1, laplaceb, rho_cutoff, [deriv_norm_drhoa], bo, &
    2140           4 :                                           weight, dra1dra, v_laplaceb%array)
    2141             :                      END IF
    2142           4 :                      IF (ASSOCIATED(norm_drhob)) THEN
    2143             :                         CALL update_deriv(deriv_set1, laplaceb, rho_cutoff, [deriv_norm_drhob], bo, &
    2144           4 :                                           weight, drb1drb, v_laplaceb%array)
    2145             :                      END IF
    2146             : 
    2147           4 :                      IF (tau_f) THEN
    2148             :                         CALL update_deriv(deriv_set1, laplaceb, rho_cutoff, [deriv_tau_a], bo, &
    2149           4 :                                           weight, tau1a, v_laplaceb%array)
    2150             :                         CALL update_deriv(deriv_set1, laplaceb, rho_cutoff, [deriv_tau_b], bo, &
    2151           4 :                                           weight, tau1b, v_laplaceb%array)
    2152             :                      END IF
    2153             : 
    2154             :                      CALL update_deriv(deriv_set1, laplaceb, rho_cutoff, [deriv_laplace_rhoa], bo, &
    2155           4 :                                        weight, laplace1a, v_laplaceb%array)
    2156             : 
    2157             :                      CALL update_deriv(deriv_set1, laplaceb, rho_cutoff, [deriv_laplace_rhob], bo, &
    2158           4 :                                        weight, laplace1b, v_laplaceb%array)
    2159             :                   END IF
    2160             :                END DO
    2161             : 
    2162          10 :                CALL virial_drho_drho(virial_pw, drhoa, v_drhoa, virial_xc)
    2163          10 :                CALL virial_drho_drho(virial_pw, drhob, v_drhob, virial_xc)
    2164          10 :                CALL virial_drho_drho(virial_pw, drho, v_drho, virial_xc)
    2165             : 
    2166          10 :                CALL deallocate_pw(v_drho, pw_pool)
    2167          10 :                CALL deallocate_pw(v_drhoa, pw_pool)
    2168          10 :                CALL deallocate_pw(v_drhob, pw_pool)
    2169             : 
    2170          10 :                IF (laplace_f) THEN
    2171       15026 :                   virial_pw%array(:, :, :) = -rhoa(:, :, :)
    2172           2 :                   CALL virial_laplace(virial_pw, pw_pool, virial_xc, v_laplacea%array)
    2173           2 :                   CALL deallocate_pw(v_laplacea, pw_pool)
    2174             : 
    2175       15026 :                   virial_pw%array(:, :, :) = -rhob(:, :, :)
    2176           2 :                   CALL virial_laplace(virial_pw, pw_pool, virial_xc, v_laplaceb%array)
    2177           2 :                   CALL deallocate_pw(v_laplaceb, pw_pool)
    2178             :                END IF
    2179             : 
    2180          10 :                CALL deallocate_pw(virial_pw, pw_pool)
    2181             : 
    2182          40 :                DO idir = 1, 3
    2183          30 :                   DEALLOCATE (drho(idir)%array)
    2184          40 :                   DEALLOCATE (drho1(idir)%array)
    2185             :                END DO
    2186          10 :                DEALLOCATE (dra1dra, drb1drb)
    2187             : 
    2188             :             ELSE
    2189          26 :                CALL xc_rho_set_get(rho1_set, rho=rho1, tau=tau1, laplace_rho=laplace1, can_return_null=.TRUE.)
    2190          26 :                CALL xc_rho_set_get(rho2_set, norm_drho=norm_drho2, laplace_rho=laplace2, can_return_null=.TRUE.)
    2191             : 
    2192         200 :                DO istep = -nsteps, nsteps
    2193         174 :                   IF (istep == 0) CYCLE
    2194         148 :                   weight = weights(istep, nsteps)/h
    2195         148 :                   step = REAL(istep, dp)*h
    2196         148 :                   CALL get_derivs_rho(norm_drho2, norm_drho, step, xc_fun_section, lsd, rho2_set, deriv_set1)
    2197             : 
    2198             :                   ! Obtain the numerical 2nd derivatives w.r.t. to drho and collect the potential
    2199             :                   CALL update_deriv_rho(deriv_set1, [deriv_rho], bo, &
    2200         148 :                                         norm_drho, gradient_cut, weight, rho1, v_drho%array)
    2201             :                   CALL update_deriv_rho(deriv_set1, [deriv_norm_drho], bo, &
    2202         148 :                                         norm_drho, gradient_cut, weight, dr1dr, v_drho%array)
    2203             : 
    2204         148 :                   IF (tau_f) THEN
    2205             :                      CALL update_deriv_rho(deriv_set1, [deriv_tau], bo, &
    2206          24 :                                            norm_drho, gradient_cut, weight, tau1, v_drho%array)
    2207             :                   END IF
    2208         174 :                   IF (laplace_f) THEN
    2209             :                      CALL update_deriv_rho(deriv_set1, [deriv_laplace_rho], bo, &
    2210          12 :                                            norm_drho, gradient_cut, weight, laplace1, v_drho%array)
    2211             : 
    2212          12 :                      CALL get_derivs_rho(laplace2, laplace, step, xc_fun_section, lsd, rho2_set, deriv_set1)
    2213             : 
    2214             :                      ! Obtain the numerical 2nd derivatives w.r.t. to drho and collect the potential
    2215             :                      CALL update_deriv(deriv_set1, laplace, rho_cutoff, [deriv_rho], bo, &
    2216          12 :                                        weight, rho1, v_laplace%array)
    2217             :                      CALL update_deriv(deriv_set1, laplace, rho_cutoff, [deriv_norm_drho], bo, &
    2218          12 :                                        weight, dr1dr, v_laplace%array)
    2219             : 
    2220          12 :                      IF (tau_f) THEN
    2221             :                         CALL update_deriv(deriv_set1, laplace, rho_cutoff, [deriv_tau], bo, &
    2222          12 :                                           weight, tau1, v_laplace%array)
    2223             :                      END IF
    2224             : 
    2225             :                      CALL update_deriv(deriv_set1, laplace, rho_cutoff, [deriv_laplace_rho], bo, &
    2226          12 :                                        weight, laplace1, v_laplace%array)
    2227             :                   END IF
    2228             :                END DO
    2229             : 
    2230             :                ! Calculate the virial contribution from the potential
    2231          26 :                CALL virial_drho_drho(virial_pw, drho, v_drho, virial_xc)
    2232             : 
    2233          26 :                CALL deallocate_pw(v_drho, pw_pool)
    2234             : 
    2235          26 :                IF (laplace_f) THEN
    2236       28862 :                   virial_pw%array(:, :, :) = -rho(:, :, :)
    2237           2 :                   CALL virial_laplace(virial_pw, pw_pool, virial_xc, v_laplace%array)
    2238           2 :                   CALL deallocate_pw(v_laplace, pw_pool)
    2239             :                END IF
    2240             : 
    2241          26 :                CALL deallocate_pw(virial_pw, pw_pool)
    2242             :             END IF
    2243             : 
    2244             :          END IF
    2245             : 
    2246          36 :          CALL xc_dset_release(deriv_set1)
    2247             : 
    2248          36 :          DEALLOCATE (dr1dr)
    2249             : 
    2250          36 :          CALL xc_rho_set_release(rho1_set)
    2251          36 :          CALL xc_rho_set_release(rho2_set)
    2252             :       END IF
    2253             : 
    2254         848 :       DO ispin = 1, SIZE(rho_r)
    2255         848 :          CALL pw_pool%give_back_pw(rho_r(ispin))
    2256             :       END DO
    2257         340 :       DEALLOCATE (rho_r)
    2258             : 
    2259         340 :       IF (ASSOCIATED(tau_r)) THEN
    2260         254 :       DO ispin = 1, SIZE(tau_r)
    2261         254 :          CALL pw_pool%give_back_pw(tau_r(ispin))
    2262             :       END DO
    2263         100 :       DEALLOCATE (tau_r)
    2264             :       END IF
    2265             : 
    2266         340 :       CALL timestop(handle)
    2267             : 
    2268       15300 :    END SUBROUTINE xc_calc_2nd_deriv_numerical
    2269             : 
    2270             : ! **************************************************************************************************
    2271             : !> \brief ...
    2272             : !> \param rho_r ...
    2273             : !> \param rho_g ...
    2274             : !> \param rho1_r ...
    2275             : !> \param rhoa ...
    2276             : !> \param rhob ...
    2277             : !> \param vxc_rho ...
    2278             : !> \param tau_r ...
    2279             : !> \param tau1_r ...
    2280             : !> \param tau_a ...
    2281             : !> \param tau_b ...
    2282             : !> \param vxc_tau ...
    2283             : !> \param xc_section ...
    2284             : !> \param pw_pool ...
    2285             : !> \param step ...
    2286             : ! **************************************************************************************************
    2287         792 :    SUBROUTINE calc_resp_potential_numer_ab(rho_r, rho_g, rho1_r, rhoa, rhob, vxc_rho, &
    2288             :                                            tau_r, tau1_r, tau_a, tau_b, vxc_tau, &
    2289             :                                            xc_section, pw_pool, step)
    2290             : 
    2291             :       TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER, INTENT(IN) :: vxc_rho, vxc_tau
    2292             :       TYPE(pw_r3d_rs_type), DIMENSION(:), INTENT(IN)            :: rho1_r
    2293             :       TYPE(pw_r3d_rs_type), DIMENSION(:), INTENT(IN), POINTER   :: tau1_r
    2294             :       TYPE(pw_pool_type), INTENT(IN), POINTER            :: pw_pool
    2295             :       TYPE(section_vals_type), INTENT(IN), POINTER       :: xc_section
    2296             :       REAL(KIND=dp), INTENT(IN)                          :: step
    2297             :       REAL(KIND=dp), DIMENSION(:, :, :), POINTER, INTENT(IN) :: rhoa, rhob, tau_a, tau_b
    2298             :       TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER, INTENT(IN)   :: rho_r
    2299             :       TYPE(pw_c1d_gs_type), DIMENSION(:), POINTER :: rho_g
    2300             :       TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER               ::  tau_r
    2301             : 
    2302             :       CHARACTER(len=*), PARAMETER :: routineN = 'calc_resp_potential_numer_ab'
    2303             : 
    2304             :       INTEGER                                            :: handle
    2305             :       REAL(KIND=dp)                                      :: exc
    2306             :       REAL(KIND=dp), DIMENSION(3, 3)                     :: virial_dummy
    2307             : 
    2308         792 :       CALL timeset(routineN, handle)
    2309             : 
    2310         792 : !$OMP PARALLEL DEFAULT(NONE) SHARED(rho_r,rhoa,rhob,step,rho1_r,tau_r,tau_a,tau_b,tau1_r)
    2311             : !$OMP WORKSHARE
    2312             :       rho_r(1)%array(:, :, :) = rhoa(:, :, :) + step*rho1_r(1)%array(:, :, :)
    2313             : !$OMP END WORKSHARE NOWAIT
    2314             : !$OMP WORKSHARE
    2315             :       rho_r(2)%array(:, :, :) = rhob(:, :, :) + step*rho1_r(2)%array(:, :, :)
    2316             : !$OMP END WORKSHARE NOWAIT
    2317             :       IF (ASSOCIATED(tau1_r) .AND. ASSOCIATED(tau_r) .AND. ASSOCIATED(tau_a) .AND. ASSOCIATED(tau_b)) THEN
    2318             : !$OMP WORKSHARE
    2319             :          tau_r(1)%array(:, :, :) = tau_a(:, :, :) + step*tau1_r(1)%array(:, :, :)
    2320             : !$OMP END WORKSHARE NOWAIT
    2321             : !$OMP WORKSHARE
    2322             :          tau_r(2)%array(:, :, :) = tau_b(:, :, :) + step*tau1_r(2)%array(:, :, :)
    2323             : !$OMP END WORKSHARE NOWAIT
    2324             :       END IF
    2325             : !$OMP END PARALLEL
    2326             :       CALL xc_vxc_pw_create(vxc_rho, vxc_tau, exc, rho_r, rho_g, tau_r, xc_section, &
    2327         792 :                             pw_pool, .FALSE., virial_dummy)
    2328             : 
    2329         792 :       CALL timestop(handle)
    2330             : 
    2331         792 :    END SUBROUTINE calc_resp_potential_numer_ab
    2332             : 
    2333             : ! **************************************************************************************************
    2334             : !> \brief calculates stress tensor and potential contributions from the first derivative
    2335             : !> \param deriv_set ...
    2336             : !> \param description ...
    2337             : !> \param virial_pw ...
    2338             : !> \param drho ...
    2339             : !> \param drho1 ...
    2340             : !> \param virial_xc ...
    2341             : !> \param norm_drho ...
    2342             : !> \param gradient_cut ...
    2343             : !> \param dr1dr ...
    2344             : !> \param v_drho ...
    2345             : ! **************************************************************************************************
    2346          52 :    SUBROUTINE apply_drho(deriv_set, description, virial_pw, drho, drho1, virial_xc, norm_drho, gradient_cut, dr1dr, v_drho)
    2347             : 
    2348             :       TYPE(xc_derivative_set_type), INTENT(IN)           :: deriv_set
    2349             :       INTEGER, DIMENSION(:), INTENT(in)                  :: description
    2350             :       TYPE(pw_r3d_rs_type), INTENT(IN)                          :: virial_pw
    2351             :       TYPE(cp_3d_r_cp_type), DIMENSION(3), INTENT(IN)     :: drho, drho1
    2352             :       REAL(KIND=dp), DIMENSION(3, 3), INTENT(INOUT)      :: virial_xc
    2353             :       REAL(KIND=dp), DIMENSION(:, :, :), INTENT(IN)      :: norm_drho
    2354             :       REAL(KIND=dp), INTENT(IN)                          :: gradient_cut
    2355             :       REAL(KIND=dp), DIMENSION(:, :, :), INTENT(IN)      :: dr1dr
    2356             :       REAL(KIND=dp), DIMENSION(:, :, :), INTENT(INOUT)   :: v_drho
    2357             : 
    2358             :       CHARACTER(len=*), PARAMETER :: routineN = 'apply_drho'
    2359             : 
    2360             :       INTEGER                                            :: handle
    2361          52 :       REAL(KIND=dp), DIMENSION(:, :, :), POINTER         :: deriv_data
    2362             :       TYPE(xc_derivative_type), POINTER                  :: deriv_att
    2363             : 
    2364          52 :       CALL timeset(routineN, handle)
    2365             : 
    2366          52 :       deriv_att => xc_dset_get_derivative(deriv_set, description)
    2367          52 :       IF (ASSOCIATED(deriv_att)) THEN
    2368          52 :          CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
    2369          52 :          CALL virial_drho_drho1(virial_pw, drho, drho1, deriv_data, virial_xc)
    2370             : 
    2371          52 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(dr1dr,gradient_cut,norm_drho,v_drho,deriv_data)
    2372             :          v_drho(:, :, :) = v_drho(:, :, :) + &
    2373             :                            deriv_data(:, :, :)*dr1dr(:, :, :)/MAX(gradient_cut, norm_drho(:, :, :))**2
    2374             : !$OMP END PARALLEL WORKSHARE
    2375             :       END IF
    2376             : 
    2377          52 :       CALL timestop(handle)
    2378             : 
    2379          52 :    END SUBROUTINE apply_drho
    2380             : 
    2381             : ! **************************************************************************************************
    2382             : !> \brief adds potential contributions from derivatives of rho or diagonal terms of norm_drho
    2383             : !> \param deriv_set1 ...
    2384             : !> \param description ...
    2385             : !> \param bo ...
    2386             : !> \param norm_drho norm_drho of which derivative is calculated
    2387             : !> \param gradient_cut ...
    2388             : !> \param h ...
    2389             : !> \param rho1 function to contract the derivative with (rho1 for rho, dr1dr for norm_drho)
    2390             : !> \param v_drho ...
    2391             : ! **************************************************************************************************
    2392         728 :    SUBROUTINE update_deriv_rho(deriv_set1, description, bo, norm_drho, gradient_cut, weight, rho1, v_drho)
    2393             : 
    2394             :       TYPE(xc_derivative_set_type), INTENT(IN)           :: deriv_set1
    2395             :       INTEGER, DIMENSION(:), INTENT(in)                  :: description
    2396             :       INTEGER, DIMENSION(2, 3), INTENT(IN)               :: bo
    2397             :       REAL(KIND=dp), DIMENSION(bo(1, 1):bo(2, 1), bo(1, &
    2398             :                                                      2):bo(2, 2), bo(1, 3):bo(2, 3)), INTENT(IN)     :: norm_drho
    2399             :       REAL(KIND=dp), INTENT(IN)                          :: gradient_cut, weight
    2400             :       REAL(KIND=dp), DIMENSION(bo(1, 1):bo(2, 1), bo(1, &
    2401             :                                                      2):bo(2, 2), bo(1, 3):bo(2, 3)), INTENT(IN)     :: rho1
    2402             :       REAL(KIND=dp), DIMENSION(bo(1, 1):bo(2, 1), bo(1, &
    2403             :                                                      2):bo(2, 2), bo(1, 3):bo(2, 3)), INTENT(INOUT)  :: v_drho
    2404             : 
    2405             :       CHARACTER(len=*), PARAMETER :: routineN = 'update_deriv_rho'
    2406             : 
    2407             :       INTEGER                                            :: handle, i, j, k
    2408             :       REAL(KIND=dp)                                      :: de
    2409         728 :       REAL(KIND=dp), DIMENSION(:, :, :), POINTER         :: deriv_data1
    2410             :       TYPE(xc_derivative_type), POINTER                  :: deriv_att1
    2411             : 
    2412         728 :       CALL timeset(routineN, handle)
    2413             : 
    2414             :       ! Obtain the numerical 2nd derivatives w.r.t. to drho and collect the potential
    2415         728 :       deriv_att1 => xc_dset_get_derivative(deriv_set1, description)
    2416         728 :       IF (ASSOCIATED(deriv_att1)) THEN
    2417         728 :          CALL xc_derivative_get(deriv_att1, deriv_data=deriv_data1)
    2418             : !$OMP PARALLEL DO DEFAULT(NONE) &
    2419             : !$OMP             SHARED(bo,deriv_data1,weight,norm_drho,v_drho,rho1,gradient_cut) &
    2420             : !$OMP             PRIVATE(i,j,k,de) &
    2421         728 : !$OMP             COLLAPSE(3)
    2422             :          DO k = bo(1, 3), bo(2, 3)
    2423             :             DO j = bo(1, 2), bo(2, 2)
    2424             :                DO i = bo(1, 1), bo(2, 1)
    2425             :                   de = weight*deriv_data1(i, j, k)/MAX(gradient_cut, norm_drho(i, j, k))**2
    2426             :                   v_drho(i, j, k) = v_drho(i, j, k) - de*rho1(i, j, k)
    2427             :                END DO
    2428             :             END DO
    2429             :          END DO
    2430             : !$OMP END PARALLEL DO
    2431             :       END IF
    2432             : 
    2433         728 :       CALL timestop(handle)
    2434             : 
    2435         728 :    END SUBROUTINE update_deriv_rho
    2436             : 
    2437             : ! **************************************************************************************************
    2438             : !> \brief adds potential contributions from derivatives of a component with positive and negative values
    2439             : !> \param deriv_set1 ...
    2440             : !> \param description ...
    2441             : !> \param bo ...
    2442             : !> \param h ...
    2443             : !> \param rho1 function to contract the derivative with (rho1 for rho, dr1dr for norm_drho)
    2444             : !> \param v ...
    2445             : ! **************************************************************************************************
    2446         120 :    SUBROUTINE update_deriv(deriv_set1, rho, rho_cutoff, description, bo, weight, rho1, v)
    2447             : 
    2448             :       TYPE(xc_derivative_set_type), INTENT(IN)           :: deriv_set1
    2449             :       INTEGER, DIMENSION(:), INTENT(in)                  :: description
    2450             :       INTEGER, DIMENSION(2, 3), INTENT(IN)               :: bo
    2451             :       REAL(KIND=dp), INTENT(IN)                          :: weight, rho_cutoff
    2452             :       REAL(KIND=dp), DIMENSION(bo(1, 1):bo(2, 1), bo(1, &
    2453             :                                                      2):bo(2, 2), bo(1, 3):bo(2, 3)), INTENT(IN)     :: rho, rho1
    2454             :       REAL(KIND=dp), DIMENSION(bo(1, 1):bo(2, 1), bo(1, &
    2455             :                                                      2):bo(2, 2), bo(1, 3):bo(2, 3)), INTENT(INOUT)  :: v
    2456             : 
    2457             :       CHARACTER(len=*), PARAMETER :: routineN = 'update_deriv'
    2458             : 
    2459             :       INTEGER                                            :: handle, i, j, k
    2460             :       REAL(KIND=dp)                                      :: de
    2461         120 :       REAL(KIND=dp), DIMENSION(:, :, :), POINTER         :: deriv_data1
    2462             :       TYPE(xc_derivative_type), POINTER                  :: deriv_att1
    2463             : 
    2464         120 :       CALL timeset(routineN, handle)
    2465             : 
    2466             :       ! Obtain the numerical 2nd derivatives w.r.t. to drho and collect the potential
    2467         120 :       deriv_att1 => xc_dset_get_derivative(deriv_set1, description)
    2468         120 :       IF (ASSOCIATED(deriv_att1)) THEN
    2469         120 :          CALL xc_derivative_get(deriv_att1, deriv_data=deriv_data1)
    2470             : !$OMP PARALLEL DO DEFAULT(NONE) &
    2471             : !$OMP             SHARED(bo,deriv_data1,weight,v,rho1,rho, rho_cutoff) &
    2472             : !$OMP             PRIVATE(i,j,k,de) &
    2473         120 : !$OMP             COLLAPSE(3)
    2474             :          DO k = bo(1, 3), bo(2, 3)
    2475             :             DO j = bo(1, 2), bo(2, 2)
    2476             :                DO i = bo(1, 1), bo(2, 1)
    2477             :                   ! We have to consider that the given density (mostly the Laplacian) may have positive and negative values
    2478             :                   de = weight*deriv_data1(i, j, k)/SIGN(MAX(ABS(rho(i, j, k)), rho_cutoff), rho(i, j, k))
    2479             :                   v(i, j, k) = v(i, j, k) + de*rho1(i, j, k)
    2480             :                END DO
    2481             :             END DO
    2482             :          END DO
    2483             : !$OMP END PARALLEL DO
    2484             :       END IF
    2485             : 
    2486         120 :       CALL timestop(handle)
    2487             : 
    2488         120 :    END SUBROUTINE update_deriv
    2489             : 
    2490             : ! **************************************************************************************************
    2491             : !> \brief adds mixed derivatives of norm_drho
    2492             : !> \param deriv_set1 ...
    2493             : !> \param description ...
    2494             : !> \param bo ...
    2495             : !> \param norm_drhoa norm_drho of which derivatives is calculated
    2496             : !> \param gradient_cut ...
    2497             : !> \param h ...
    2498             : !> \param dra1dra dr1dr corresponding to norm_drho
    2499             : !> \param drb1drb ...
    2500             : !> \param v_drhoa potential corresponding to norm_drho
    2501             : !> \param v_drhob ...
    2502             : ! **************************************************************************************************
    2503         216 :    SUBROUTINE update_deriv_drho_ab(deriv_set1, description, bo, &
    2504         216 :                                    norm_drhoa, gradient_cut, weight, dra1dra, drb1drb, v_drhoa, v_drhob)
    2505             : 
    2506             :       TYPE(xc_derivative_set_type), INTENT(IN)           :: deriv_set1
    2507             :       INTEGER, DIMENSION(:), INTENT(in)                  :: description
    2508             :       INTEGER, DIMENSION(2, 3), INTENT(IN)               :: bo
    2509             :       REAL(KIND=dp), DIMENSION(bo(1, 1):bo(2, 1), bo(1, &
    2510             :                                                      2):bo(2, 2), bo(1, 3):bo(2, 3)), INTENT(IN)     :: norm_drhoa
    2511             :       REAL(KIND=dp), INTENT(IN)                          :: gradient_cut, weight
    2512             :       REAL(KIND=dp), DIMENSION(bo(1, 1):bo(2, 1), bo(1, &
    2513             :                                                      2):bo(2, 2), bo(1, 3):bo(2, 3)), INTENT(IN)     :: dra1dra, drb1drb
    2514             :       REAL(KIND=dp), DIMENSION(bo(1, 1):bo(2, 1), bo(1, &
    2515             :                                                      2):bo(2, 2), bo(1, 3):bo(2, 3)), INTENT(INOUT)  :: v_drhoa, v_drhob
    2516             : 
    2517             :       CHARACTER(len=*), PARAMETER :: routineN = 'update_deriv_drho_ab'
    2518             : 
    2519             :       INTEGER                                            :: handle, i, j, k
    2520             :       REAL(KIND=dp)                                      :: de
    2521         216 :       REAL(KIND=dp), DIMENSION(:, :, :), POINTER         :: deriv_data1
    2522             :       TYPE(xc_derivative_type), POINTER                  :: deriv_att1
    2523             : 
    2524         216 :       CALL timeset(routineN, handle)
    2525             : 
    2526         216 :       deriv_att1 => xc_dset_get_derivative(deriv_set1, description)
    2527         216 :       IF (ASSOCIATED(deriv_att1)) THEN
    2528         168 :          CALL xc_derivative_get(deriv_att1, deriv_data=deriv_data1)
    2529             : !$OMP PARALLEL DO DEFAULT(NONE) &
    2530             : !$OMP             PRIVATE(k,j,i,de) &
    2531             : !$OMP             SHARED(bo,drb1drb,dra1dra,deriv_data1,weight,gradient_cut,norm_drhoa,v_drhoa,v_drhob) &
    2532         168 : !$OMP             COLLAPSE(3)
    2533             :          DO k = bo(1, 3), bo(2, 3)
    2534             :             DO j = bo(1, 2), bo(2, 2)
    2535             :                DO i = bo(1, 1), bo(2, 1)
    2536             :                   ! We introduce a factor of two because we will average between both numerical derivatives
    2537             :                   de = 0.5_dp*weight*deriv_data1(i, j, k)/MAX(gradient_cut, norm_drhoa(i, j, k))**2
    2538             :                   v_drhoa(i, j, k) = v_drhoa(i, j, k) - de*drb1drb(i, j, k)
    2539             :                   v_drhob(i, j, k) = v_drhob(i, j, k) - de*dra1dra(i, j, k)
    2540             :                END DO
    2541             :             END DO
    2542             :          END DO
    2543             : !$OMP END PARALLEL DO
    2544             :       END IF
    2545             : 
    2546         216 :       CALL timestop(handle)
    2547             : 
    2548         216 :    END SUBROUTINE update_deriv_drho_ab
    2549             : 
    2550             : ! **************************************************************************************************
    2551             : !> \brief calculate derivative sets for helper points
    2552             : !> \param norm_drho2 norm_drho of new points
    2553             : !> \param norm_drho norm_drho of KS density
    2554             : !> \param h ...
    2555             : !> \param xc_fun_section ...
    2556             : !> \param lsd ...
    2557             : !> \param rho2_set rho_set for new points
    2558             : !> \param deriv_set1 will contain derivatives of the perturbed density
    2559             : ! **************************************************************************************************
    2560         276 :    SUBROUTINE get_derivs_rho(norm_drho2, norm_drho, step, xc_fun_section, lsd, rho2_set, deriv_set1)
    2561             :       REAL(KIND=dp), DIMENSION(:, :, :), INTENT(OUT)     :: norm_drho2
    2562             :       REAL(KIND=dp), DIMENSION(:, :, :), INTENT(IN)      :: norm_drho
    2563             :       REAL(KIND=dp), INTENT(IN)                          :: step
    2564             :       TYPE(section_vals_type), INTENT(IN), POINTER       :: xc_fun_section
    2565             :       LOGICAL, INTENT(IN)                                :: lsd
    2566             :       TYPE(xc_rho_set_type), INTENT(INOUT)               :: rho2_set
    2567             :       TYPE(xc_derivative_set_type)                       :: deriv_set1
    2568             : 
    2569             :       CHARACTER(len=*), PARAMETER :: routineN = 'get_derivs_rho'
    2570             : 
    2571             :       INTEGER                                            :: handle
    2572             : 
    2573         276 :       CALL timeset(routineN, handle)
    2574             : 
    2575             :       ! Copy the densities, do one step into the direction of drho
    2576         276 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(norm_drho,norm_drho2,step)
    2577             :       norm_drho2 = norm_drho*(1.0_dp + step)
    2578             : !$OMP END PARALLEL WORKSHARE
    2579             : 
    2580         276 :       CALL xc_dset_zero_all(deriv_set1)
    2581             : 
    2582             :       ! Calculate the derivatives of the functional
    2583             :       CALL xc_functionals_eval(xc_fun_section, &
    2584             :                                lsd=lsd, &
    2585             :                                rho_set=rho2_set, &
    2586             :                                deriv_set=deriv_set1, &
    2587         276 :                                deriv_order=1)
    2588             : 
    2589             :       ! Return to the original values
    2590         276 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(norm_drho,norm_drho2)
    2591             :       norm_drho2 = norm_drho
    2592             : !$OMP END PARALLEL WORKSHARE
    2593             : 
    2594         276 :       CALL divide_by_norm_drho(deriv_set1, rho2_set, lsd)
    2595             : 
    2596         276 :       CALL timestop(handle)
    2597             : 
    2598         276 :    END SUBROUTINE get_derivs_rho
    2599             : 
    2600             : ! **************************************************************************************************
    2601             : !> \brief Calculates the second derivative of E_xc at rho in the direction
    2602             : !>      rho1  (if you see the second derivative as bilinear form)
    2603             : !>      partial_rho|_(rho=rho) partial_rho|_(rho=rho) E_xc drho(rho1)drho
    2604             : !>      The other direction is still undetermined, thus it returns
    2605             : !>      a potential (partial integration is performed to reduce it to
    2606             : !>      function of rho, removing the dependence from its partial derivs)
    2607             : !>      Has to be called after the setup by xc_prep_2nd_deriv.
    2608             : !> \param v_xc       exchange-correlation potential
    2609             : !> \param v_xc_tau ...
    2610             : !> \param deriv_set  derivatives of the exchange-correlation potential
    2611             : !> \param rho_set    object containing the density at which the derivatives were calculated
    2612             : !> \param rho1_set   object containing the density with which to fold
    2613             : !> \param pw_pool    the pool for the grids
    2614             : !> \param xc_section XC parameters
    2615             : !> \param gapw       Gaussian and augmented plane waves calculation
    2616             : !> \param vxg ...
    2617             : !> \param tddfpt_fac factor that multiplies the crossterms (tddfpt triplets
    2618             : !>        on a closed shell system it should be -1, defaults to 1)
    2619             : !> \param compute_virial ...
    2620             : !> \param virial_xc ...
    2621             : !> \note
    2622             : !>      The old version of this routine was smarter: it handled split_desc(1)
    2623             : !>      and split_desc(2) separately, thus the code automatically handled all
    2624             : !>      possible cross terms (you only had to check if it was diagonal to avoid
    2625             : !>      double counting). I think that is the way to go if you want to add more
    2626             : !>      terms (tau,rho in LSD,...). The problem with the old code was that it
    2627             : !>      because of the old functional structure it sometime guessed wrongly
    2628             : !>      which derivative was where. There were probably still bugs with gradient
    2629             : !>      corrected functionals (never tested), and it didn't contain first
    2630             : !>      derivatives with respect to drho (that contribute also to the second
    2631             : !>      derivative wrt. rho).
    2632             : !>      The code was a little complex because it really tried to handle any
    2633             : !>      functional derivative in the most efficient way with the given contents of
    2634             : !>      rho_set.
    2635             : !>      Anyway I strongly encourage whoever wants to modify this code to give a
    2636             : !>      look to the old version. [fawzi]
    2637             : ! **************************************************************************************************
    2638       30330 :    SUBROUTINE xc_calc_2nd_deriv_analytical(v_xc, v_xc_tau, deriv_set, rho_set, rho1_set, &
    2639             :                                            pw_pool, xc_section, gapw, vxg, tddfpt_fac, &
    2640             :                                            compute_virial, virial_xc)
    2641             : 
    2642             :       TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER             :: v_xc, v_xc_tau
    2643             :       TYPE(xc_derivative_set_type)                       :: deriv_set
    2644             :       TYPE(xc_rho_set_type), INTENT(IN)                  :: rho_set, rho1_set
    2645             :       TYPE(pw_pool_type), POINTER                        :: pw_pool
    2646             :       TYPE(section_vals_type), POINTER                   :: xc_section
    2647             :       LOGICAL, INTENT(IN), OPTIONAL                      :: gapw
    2648             :       REAL(kind=dp), DIMENSION(:, :, :, :), OPTIONAL, &
    2649             :          POINTER                                         :: vxg
    2650             :       REAL(kind=dp), INTENT(in), OPTIONAL                :: tddfpt_fac
    2651             :       LOGICAL, INTENT(IN), OPTIONAL                      :: compute_virial
    2652             :       REAL(KIND=dp), DIMENSION(3, 3), INTENT(INOUT), &
    2653             :          OPTIONAL                                        :: virial_xc
    2654             : 
    2655             :       CHARACTER(len=*), PARAMETER :: routineN = 'xc_calc_2nd_deriv_analytical'
    2656             : 
    2657             :       INTEGER                                            :: handle, i, ia, idir, ir, ispin, j, jdir, &
    2658             :                                                             k, nspins, xc_deriv_method_id
    2659             :       INTEGER, DIMENSION(2, 3)                           :: bo
    2660             :       LOGICAL                                            :: gradient_f, lsd, my_compute_virial, &
    2661             :                                                             my_gapw, tau_f, laplace_f, rho_f
    2662             :       REAL(KIND=dp)                                      :: fac, gradient_cut, tmp, factor2
    2663       30330 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: dr1dr, dra1dra, drb1drb
    2664       60660 :       REAL(kind=dp), DIMENSION(:, :, :), POINTER         :: deriv_data, e_drhoa, e_drhob, &
    2665       30330 :                                                             e_drho, norm_drho, norm_drhoa, &
    2666       30330 :                                                             norm_drhob, rho1, rho1a, rho1b, &
    2667       30330 :                                                             tau1, tau1a, tau1b, laplace1, laplace1a, laplace1b, &
    2668       30330 :                                                             rho, rhoa, rhob
    2669      576270 :       TYPE(cp_3d_r_cp_type), DIMENSION(3)                :: drho, drho1, drho1a, drho1b, drhoa, drhob
    2670       30330 :       TYPE(pw_r3d_rs_type), DIMENSION(:), ALLOCATABLE         :: v_drhoa, v_drhob, v_drho, v_laplace
    2671       30330 :       TYPE(pw_r3d_rs_type), DIMENSION(:, :), ALLOCATABLE      :: v_drho_r
    2672             :       TYPE(pw_r3d_rs_type)                                      ::  virial_pw
    2673             :       TYPE(pw_c1d_gs_type) :: tmp_g, vxc_g
    2674             :       TYPE(xc_derivative_type), POINTER                  :: deriv_att
    2675             : 
    2676       30330 :       CALL timeset(routineN, handle)
    2677             : 
    2678       30330 :       NULLIFY (e_drhoa, e_drhob, e_drho)
    2679             : 
    2680       30330 :       my_gapw = .FALSE.
    2681       30330 :       IF (PRESENT(gapw)) my_gapw = gapw
    2682             : 
    2683       30330 :       my_compute_virial = .FALSE.
    2684       30330 :       IF (PRESENT(compute_virial)) my_compute_virial = compute_virial
    2685             : 
    2686       30330 :       CPASSERT(ASSOCIATED(v_xc))
    2687       30330 :       CPASSERT(ASSOCIATED(xc_section))
    2688       30330 :       IF (my_gapw) THEN
    2689        9596 :          CPASSERT(PRESENT(vxg))
    2690             :       END IF
    2691       30330 :       IF (my_compute_virial) THEN
    2692         358 :          CPASSERT(PRESENT(virial_xc))
    2693             :       END IF
    2694             : 
    2695             :       CALL section_vals_val_get(xc_section, "XC_GRID%XC_DERIV", &
    2696       30330 :                                 i_val=xc_deriv_method_id)
    2697       30330 :       CALL xc_rho_set_get(rho_set, drho_cutoff=gradient_cut)
    2698       30330 :       nspins = SIZE(v_xc)
    2699       30330 :       lsd = ASSOCIATED(rho_set%rhoa)
    2700       30330 :       fac = 0.0_dp
    2701       30330 :       factor2 = 1.0_dp
    2702       30330 :       IF (PRESENT(tddfpt_fac)) fac = tddfpt_fac
    2703       30330 :       IF (PRESENT(tddfpt_fac)) factor2 = tddfpt_fac
    2704             : 
    2705      303300 :       bo = rho_set%local_bounds
    2706             : 
    2707       30330 :       CALL check_for_derivatives(deriv_set, lsd, rho_f, gradient_f, tau_f, laplace_f)
    2708             : 
    2709       30330 :       IF (tau_f) THEN
    2710         656 :          CPASSERT(ASSOCIATED(v_xc_tau))
    2711             :       END IF
    2712             : 
    2713       30330 :       IF (gradient_f) THEN
    2714      195750 :          ALLOCATE (v_drho_r(3, nspins), v_drho(nspins))
    2715       39150 :          DO ispin = 1, nspins
    2716       80880 :             DO idir = 1, 3
    2717       80880 :                CALL allocate_pw(v_drho_r(idir, ispin), pw_pool, bo)
    2718             :             END DO
    2719       39150 :             CALL allocate_pw(v_drho(ispin), pw_pool, bo)
    2720             :          END DO
    2721             : 
    2722       18930 :          IF (xc_requires_tmp_g(xc_deriv_method_id) .AND. .NOT. my_gapw) THEN
    2723       11476 :             IF (ASSOCIATED(pw_pool)) THEN
    2724       11476 :                CALL pw_pool%create_pw(tmp_g)
    2725       11476 :                CALL pw_pool%create_pw(vxc_g)
    2726             :             ELSE
    2727             :                ! remember to refix for gapw
    2728           0 :                CPABORT("XC_DERIV method is not implemented in GAPW")
    2729             :             END IF
    2730             :          END IF
    2731             :       END IF
    2732             : 
    2733       63854 :       DO ispin = 1, nspins
    2734   945639375 :          v_xc(ispin)%array = 0.0_dp
    2735             :       END DO
    2736             : 
    2737       30330 :       IF (tau_f) THEN
    2738        1386 :          DO ispin = 1, nspins
    2739    14897758 :             v_xc_tau(ispin)%array = 0.0_dp
    2740             :          END DO
    2741             :       END IF
    2742             : 
    2743       30330 :       IF (laplace_f .AND. my_gapw) &
    2744           0 :          CPABORT("Laplace-dependent functional not implemented with GAPW!")
    2745             : 
    2746       30330 :       IF (my_compute_virial .AND. (gradient_f .OR. laplace_f)) CALL allocate_pw(virial_pw, pw_pool, bo)
    2747             : 
    2748       30330 :       IF (lsd) THEN
    2749             : 
    2750             :          !-------------------!
    2751             :          ! UNrestricted case !
    2752             :          !-------------------!
    2753             : 
    2754        4232 :          CALL xc_rho_set_get(rho1_set, rhoa=rho1a, rhob=rho1b)
    2755             : 
    2756        4232 :          IF (gradient_f) THEN
    2757             :             CALL xc_rho_set_get(rho_set, drhoa=drhoa, drhob=drhob, &
    2758        2000 :                                 norm_drho=norm_drho, norm_drhoa=norm_drhoa, norm_drhob=norm_drhob)
    2759        2000 :             CALL xc_rho_set_get(rho1_set, drhoa=drho1a, drhob=drho1b)
    2760             : 
    2761        2000 :             CALL calc_drho_from_ab(drho, drhoa, drhob)
    2762        2000 :             CALL calc_drho_from_ab(drho1, drho1a, drho1b)
    2763             : 
    2764        2000 :             CALL prepare_dr1dr(dra1dra, drhoa, drho1a)
    2765        2000 :             IF (nspins /= 1) THEN
    2766        1290 :                CALL prepare_dr1dr(drb1drb, drhob, drho1b)
    2767        1290 :                CALL prepare_dr1dr(dr1dr, drho, drho1)
    2768             :             ELSE
    2769         710 :                CALL prepare_dr1dr(drb1drb, drhob, drho1b)
    2770         710 :                CALL prepare_dr1dr_ab(dr1dr, drhoa, drhob, drho1a, drho1b, fac)
    2771             :             END IF
    2772             : 
    2773       14580 :             ALLOCATE (v_drhoa(nspins), v_drhob(nspins))
    2774        5290 :             DO ispin = 1, nspins
    2775        3290 :                CALL allocate_pw(v_drhoa(ispin), pw_pool, bo)
    2776        5290 :                CALL allocate_pw(v_drhob(ispin), pw_pool, bo)
    2777             :             END DO
    2778             : 
    2779             :          END IF
    2780             : 
    2781        4232 :          IF (laplace_f) THEN
    2782          38 :             CALL xc_rho_set_get(rho1_set, laplace_rhoa=laplace1a, laplace_rhob=laplace1b)
    2783             : 
    2784         190 :             ALLOCATE (v_laplace(nspins))
    2785         114 :             DO ispin = 1, nspins
    2786         114 :                CALL allocate_pw(v_laplace(ispin), pw_pool, bo)
    2787             :             END DO
    2788             : 
    2789          38 :             IF (my_compute_virial) CALL xc_rho_set_get(rho_set, rhoa=rhoa, rhob=rhob)
    2790             :          END IF
    2791             : 
    2792        4232 :          IF (tau_f) THEN
    2793          74 :             CALL xc_rho_set_get(rho1_set, tau_a=tau1a, tau_b=tau1b)
    2794             :          END IF
    2795             : 
    2796        4232 :          IF (nspins /= 1) THEN
    2797             : 
    2798       33242 :             $:add_2nd_derivative_terms(arguments_openshell)
    2799             : 
    2800             :          ELSE
    2801             : 
    2802        1038 :             $:add_2nd_derivative_terms(arguments_triplet_outer, arguments_triplet_inner)
    2803             : 
    2804             :          END IF
    2805             : 
    2806        4232 :          IF (gradient_f) THEN
    2807             : 
    2808        2000 :             IF (my_compute_virial) THEN
    2809          10 :                CALL virial_drho_drho(virial_pw, drhoa, v_drhoa(1), virial_xc)
    2810          10 :                CALL virial_drho_drho(virial_pw, drhob, v_drhob(2), virial_xc)
    2811          40 :                DO idir = 1, 3
    2812          30 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(drho,idir,v_drho,virial_pw)
    2813             :                   virial_pw%array(:, :, :) = drho(idir)%array(:, :, :)*(v_drho(1)%array(:, :, :) + v_drho(2)%array(:, :, :))
    2814             : !$OMP END PARALLEL WORKSHARE
    2815         100 :                   DO jdir = 1, idir
    2816             :                      tmp = -0.5_dp*virial_pw%pw_grid%dvol*accurate_dot_product(virial_pw%array(:, :, :), &
    2817          60 :                                                                                drho(jdir)%array(:, :, :))
    2818          60 :                      virial_xc(jdir, idir) = virial_xc(jdir, idir) + tmp
    2819          90 :                      virial_xc(idir, jdir) = virial_xc(jdir, idir)
    2820             :                   END DO
    2821             :                END DO
    2822             :             END IF ! my_compute_virial
    2823             : 
    2824        2000 :             IF (my_gapw) THEN
    2825             : !$OMP PARALLEL DO DEFAULT(NONE) &
    2826             : !$OMP             PRIVATE(ia,idir,ispin,ir) &
    2827             : !$OMP             SHARED(bo,nspins,vxg,drhoa,drhob,v_drhoa,v_drhob,v_drho, &
    2828             : !$OMP                    e_drhoa,e_drhob,e_drho,drho1a,drho1b,fac,drho,drho1) &
    2829         524 : !$OMP             COLLAPSE(3)
    2830             :                DO ir = bo(1, 2), bo(2, 2)
    2831             :                   DO ia = bo(1, 1), bo(2, 1)
    2832             :                      DO idir = 1, 3
    2833             :                         DO ispin = 1, nspins
    2834             :                            vxg(idir, ia, ir, ispin) = &
    2835             :                               -(v_drhoa(ispin)%array(ia, ir, 1)*drhoa(idir)%array(ia, ir, 1) + &
    2836             :                                 v_drhob(ispin)%array(ia, ir, 1)*drhob(idir)%array(ia, ir, 1) + &
    2837             :                                 v_drho(ispin)%array(ia, ir, 1)*drho(idir)%array(ia, ir, 1))
    2838             :                         END DO
    2839             :                         IF (ASSOCIATED(e_drhoa)) THEN
    2840             :                            vxg(idir, ia, ir, 1) = vxg(idir, ia, ir, 1) + &
    2841             :                                                   e_drhoa(ia, ir, 1)*drho1a(idir)%array(ia, ir, 1)
    2842             :                         END IF
    2843             :                         IF (nspins /= 1 .AND. ASSOCIATED(e_drhob)) THEN
    2844             :                            vxg(idir, ia, ir, 2) = vxg(idir, ia, ir, 2) + &
    2845             :                                                   e_drhob(ia, ir, 1)*drho1b(idir)%array(ia, ir, 1)
    2846             :                         END IF
    2847             :                         IF (ASSOCIATED(e_drho)) THEN
    2848             :                            IF (nspins /= 1) THEN
    2849             :                               vxg(idir, ia, ir, 1) = vxg(idir, ia, ir, 1) + &
    2850             :                                                      e_drho(ia, ir, 1)*drho1(idir)%array(ia, ir, 1)
    2851             :                               vxg(idir, ia, ir, 2) = vxg(idir, ia, ir, 2) + &
    2852             :                                                      e_drho(ia, ir, 1)*drho1(idir)%array(ia, ir, 1)
    2853             :                            ELSE
    2854             :                               vxg(idir, ia, ir, 1) = vxg(idir, ia, ir, 1) + &
    2855             :                                                      e_drho(ia, ir, 1)*(drho1a(idir)%array(ia, ir, 1) + &
    2856             :                                                                         fac*drho1b(idir)%array(ia, ir, 1))
    2857             :                            END IF
    2858             :                         END IF
    2859             :                      END DO
    2860             :                   END DO
    2861             :                END DO
    2862             : !$OMP END PARALLEL DO
    2863             :             ELSE
    2864             : 
    2865             :                ! partial integration
    2866        5904 :                DO idir = 1, 3
    2867             : 
    2868       12342 :                   DO ispin = 1, nspins
    2869       12342 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(v_drho_r,v_drhoa,v_drhob,v_drho,drhoa,drhob,drho,ispin,idir)
    2870             :                      v_drho_r(idir, ispin)%array(:, :, :) = &
    2871             :                         v_drhoa(ispin)%array(:, :, :)*drhoa(idir)%array(:, :, :) + &
    2872             :                         v_drhob(ispin)%array(:, :, :)*drhob(idir)%array(:, :, :) + &
    2873             :                         v_drho(ispin)%array(:, :, :)*drho(idir)%array(:, :, :)
    2874             : !$OMP END PARALLEL WORKSHARE
    2875             :                   END DO
    2876        4428 :                   IF (ASSOCIATED(e_drhoa)) THEN
    2877        4428 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(v_drho_r,e_drhoa,drho1a,idir)
    2878             :                      v_drho_r(idir, 1)%array(:, :, :) = v_drho_r(idir, 1)%array(:, :, :) - &
    2879             :                                                         e_drhoa(:, :, :)*drho1a(idir)%array(:, :, :)
    2880             : !$OMP END PARALLEL WORKSHARE
    2881             :                   END IF
    2882        4428 :                   IF (nspins /= 1 .AND. ASSOCIATED(e_drhob)) THEN
    2883        3486 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(v_drho_r,e_drhob,drho1b,idir)
    2884             :                      v_drho_r(idir, 2)%array(:, :, :) = v_drho_r(idir, 2)%array(:, :, :) - &
    2885             :                                                         e_drhob(:, :, :)*drho1b(idir)%array(:, :, :)
    2886             : !$OMP END PARALLEL WORKSHARE
    2887             :                   END IF
    2888        5904 :                   IF (ASSOCIATED(e_drho)) THEN
    2889             : !$OMP PARALLEL DO DEFAULT(NONE) &
    2890             : !$OMP              PRIVATE(k,j,i) &
    2891             : !$OMP              SHARED(bo,v_drho_r,e_drho,drho1a,drho1b,drho1,fac,idir,nspins) &
    2892        4428 : !$OMP              COLLAPSE(3)
    2893             :                      DO k = bo(1, 3), bo(2, 3)
    2894             :                         DO j = bo(1, 2), bo(2, 2)
    2895             :                            DO i = bo(1, 1), bo(2, 1)
    2896             :                               IF (nspins /= 1) THEN
    2897             :                                  v_drho_r(idir, 1)%array(i, j, k) = v_drho_r(idir, 1)%array(i, j, k) - &
    2898             :                                                                     e_drho(i, j, k)*drho1(idir)%array(i, j, k)
    2899             :                                  v_drho_r(idir, 2)%array(i, j, k) = v_drho_r(idir, 2)%array(i, j, k) - &
    2900             :                                                                     e_drho(i, j, k)*drho1(idir)%array(i, j, k)
    2901             :                               ELSE
    2902             :                                  v_drho_r(idir, 1)%array(i, j, k) = v_drho_r(idir, 1)%array(i, j, k) - &
    2903             :                                                                     e_drho(i, j, k)*(drho1a(idir)%array(i, j, k) + &
    2904             :                                                                                      fac*drho1b(idir)%array(i, j, k))
    2905             :                               END IF
    2906             :                            END DO
    2907             :                         END DO
    2908             :                      END DO
    2909             : !$OMP END PARALLEL DO
    2910             :                   END IF
    2911             :                END DO
    2912             : 
    2913        4114 :                DO ispin = 1, nspins
    2914             :                   ! partial integration
    2915        4114 :                   CALL xc_pw_divergence(xc_deriv_method_id, v_drho_r(:, ispin), tmp_g, vxc_g, v_xc(ispin))
    2916             :                END DO ! ispin
    2917             : 
    2918             :             END IF
    2919             : 
    2920        8000 :             DO idir = 1, 3
    2921        6000 :                DEALLOCATE (drho(idir)%array)
    2922        8000 :                DEALLOCATE (drho1(idir)%array)
    2923             :             END DO
    2924             : 
    2925        5290 :             DO ispin = 1, nspins
    2926        3290 :                CALL deallocate_pw(v_drhoa(ispin), pw_pool)
    2927        5290 :                CALL deallocate_pw(v_drhob(ispin), pw_pool)
    2928             :             END DO
    2929             : 
    2930        2000 :             DEALLOCATE (v_drhoa, v_drhob)
    2931             : 
    2932             :          END IF ! gradient_f
    2933             : 
    2934        4232 :          IF (laplace_f .AND. my_compute_virial) THEN
    2935       15026 :             virial_pw%array(:, :, :) = -rhoa(:, :, :)
    2936           2 :             CALL virial_laplace(virial_pw, pw_pool, virial_xc, v_laplace(1)%array)
    2937       15026 :             virial_pw%array(:, :, :) = -rhob(:, :, :)
    2938           2 :             CALL virial_laplace(virial_pw, pw_pool, virial_xc, v_laplace(2)%array)
    2939             :          END IF
    2940             : 
    2941             :       ELSE
    2942             : 
    2943             :          !-----------------!
    2944             :          ! restricted case !
    2945             :          !-----------------!
    2946             : 
    2947       26098 :          CALL xc_rho_set_get(rho1_set, rho=rho1)
    2948             : 
    2949       26098 :          IF (gradient_f) THEN
    2950       16930 :             CALL xc_rho_set_get(rho_set, drho=drho, norm_drho=norm_drho)
    2951       16930 :             CALL xc_rho_set_get(rho1_set, drho=drho1)
    2952       16930 :             CALL prepare_dr1dr(dr1dr, drho, drho1)
    2953             :          END IF
    2954             : 
    2955       26098 :          IF (laplace_f) THEN
    2956         136 :             CALL xc_rho_set_get(rho1_set, laplace_rho=laplace1)
    2957             : 
    2958         544 :             ALLOCATE (v_laplace(nspins))
    2959         272 :             DO ispin = 1, nspins
    2960         272 :                CALL allocate_pw(v_laplace(ispin), pw_pool, bo)
    2961             :             END DO
    2962             : 
    2963         136 :             IF (my_compute_virial) CALL xc_rho_set_get(rho_set, rho=rho)
    2964             :          END IF
    2965             : 
    2966       26098 :          IF (tau_f) THEN
    2967         582 :             CALL xc_rho_set_get(rho1_set, tau=tau1)
    2968             :          END IF
    2969             : 
    2970      320614 :          $:add_2nd_derivative_terms(arguments_closedshell)
    2971             : 
    2972       26098 :          IF (gradient_f) THEN
    2973             : 
    2974       16930 :             IF (my_compute_virial) THEN
    2975         222 :                CALL virial_drho_drho(virial_pw, drho, v_drho(1), virial_xc)
    2976             :             END IF ! my_compute_virial
    2977             : 
    2978       16930 :             IF (my_gapw) THEN
    2979             : 
    2980       26056 :                DO idir = 1, 3
    2981             : !$OMP PARALLEL DO DEFAULT(NONE) &
    2982             : !$OMP             PRIVATE(ia,ir) &
    2983             : !$OMP             SHARED(bo,vxg,drho,v_drho,e_drho,drho1,idir,factor2) &
    2984       26056 : !$OMP             COLLAPSE(2)
    2985             :                   DO ia = bo(1, 1), bo(2, 1)
    2986             :                      DO ir = bo(1, 2), bo(2, 2)
    2987             :                         vxg(idir, ia, ir, 1) = -drho(idir)%array(ia, ir, 1)*v_drho(1)%array(ia, ir, 1)
    2988             :                         IF (ASSOCIATED(e_drho)) THEN
    2989             :                            vxg(idir, ia, ir, 1) = vxg(idir, ia, ir, 1) + factor2*drho1(idir)%array(ia, ir, 1)*e_drho(ia, ir, 1)
    2990             :                         END IF
    2991             :                      END DO
    2992             :                   END DO
    2993             : !$OMP END PARALLEL DO
    2994             :                END DO
    2995             : 
    2996             :             ELSE
    2997             :                ! partial integration
    2998       41664 :                DO idir = 1, 3
    2999       41664 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(v_drho_r,drho,v_drho,drho1,e_drho,idir)
    3000             :                   v_drho_r(idir, 1)%array(:, :, :) = drho(idir)%array(:, :, :)*v_drho(1)%array(:, :, :) - &
    3001             :                                                      drho1(idir)%array(:, :, :)*e_drho(:, :, :)
    3002             : !$OMP END PARALLEL WORKSHARE
    3003             :                END DO
    3004             : 
    3005       10416 :                CALL xc_pw_divergence(xc_deriv_method_id, v_drho_r(:, 1), tmp_g, vxc_g, v_xc(1))
    3006             :             END IF
    3007             : 
    3008             :          END IF
    3009             : 
    3010       26098 :          IF (laplace_f .AND. my_compute_virial) THEN
    3011      294530 :             virial_pw%array(:, :, :) = -rho(:, :, :)
    3012          14 :             CALL virial_laplace(virial_pw, pw_pool, virial_xc, v_laplace(1)%array)
    3013             :          END IF
    3014             : 
    3015             :       END IF
    3016             : 
    3017       30330 :       IF (laplace_f) THEN
    3018         386 :          DO ispin = 1, nspins
    3019         212 :             CALL xc_pw_laplace(v_laplace(ispin), pw_pool, xc_deriv_method_id)
    3020         386 :             CALL pw_axpy(v_laplace(ispin), v_xc(ispin))
    3021             :          END DO
    3022             :       END IF
    3023             : 
    3024       30330 :       IF (gradient_f) THEN
    3025             : 
    3026       39150 :          DO ispin = 1, nspins
    3027       20220 :             CALL deallocate_pw(v_drho(ispin), pw_pool)
    3028       99810 :             DO idir = 1, 3
    3029       80880 :                CALL deallocate_pw(v_drho_r(idir, ispin), pw_pool)
    3030             :             END DO
    3031             :          END DO
    3032       18930 :          DEALLOCATE (v_drho, v_drho_r)
    3033             : 
    3034             :       END IF
    3035             : 
    3036       30330 :       IF (laplace_f) THEN
    3037         386 :       DO ispin = 1, nspins
    3038         386 :          CALL deallocate_pw(v_laplace(ispin), pw_pool)
    3039             :       END DO
    3040         174 :       DEALLOCATE (v_laplace)
    3041             :       END IF
    3042             : 
    3043       30330 :       IF (ASSOCIATED(tmp_g%pw_grid) .AND. ASSOCIATED(pw_pool)) THEN
    3044       11476 :          CALL pw_pool%give_back_pw(tmp_g)
    3045             :       END IF
    3046             : 
    3047       30330 :       IF (ASSOCIATED(vxc_g%pw_grid) .AND. ASSOCIATED(pw_pool)) THEN
    3048       11476 :          CALL pw_pool%give_back_pw(vxc_g)
    3049             :       END IF
    3050             : 
    3051       30330 :       IF (my_compute_virial .AND. (gradient_f .OR. laplace_f)) THEN
    3052         232 :          CALL deallocate_pw(virial_pw, pw_pool)
    3053             :       END IF
    3054             : 
    3055       30330 :       CALL timestop(handle)
    3056             : 
    3057       90990 :    END SUBROUTINE xc_calc_2nd_deriv_analytical
    3058             : 
    3059             : ! **************************************************************************************************
    3060             : !> \brief allocates grids using pw_pool (if associated) or with bounds
    3061             : !> \param pw ...
    3062             : !> \param pw_pool ...
    3063             : !> \param bo ...
    3064             : ! **************************************************************************************************
    3065       88002 :    SUBROUTINE allocate_pw(pw, pw_pool, bo)
    3066             :       TYPE(pw_r3d_rs_type), INTENT(OUT)                         :: pw
    3067             :       TYPE(pw_pool_type), INTENT(IN), POINTER            :: pw_pool
    3068             :       INTEGER, DIMENSION(2, 3), INTENT(IN)               :: bo
    3069             : 
    3070       88002 :       IF (ASSOCIATED(pw_pool)) THEN
    3071       58034 :          CALL pw_pool%create_pw(pw)
    3072       58034 :          CALL pw_zero(pw)
    3073             :       ELSE
    3074      149840 :          ALLOCATE (pw%array(bo(1, 1):bo(2, 1), bo(1, 2):bo(2, 2), bo(1, 3):bo(2, 3)))
    3075    76478336 :          pw%array = 0.0_dp
    3076             :       END IF
    3077             : 
    3078       88002 :    END SUBROUTINE allocate_pw
    3079             : 
    3080             : ! **************************************************************************************************
    3081             : !> \brief deallocates grid allocated with allocate_pw
    3082             : !> \param pw ...
    3083             : !> \param pw_pool ...
    3084             : ! **************************************************************************************************
    3085       88002 :    SUBROUTINE deallocate_pw(pw, pw_pool)
    3086             :       TYPE(pw_r3d_rs_type), INTENT(INOUT)                       :: pw
    3087             :       TYPE(pw_pool_type), INTENT(IN), POINTER            :: pw_pool
    3088             : 
    3089       88002 :       IF (ASSOCIATED(pw_pool)) THEN
    3090       58034 :          CALL pw_pool%give_back_pw(pw)
    3091             :       ELSE
    3092       29968 :          CALL pw%release()
    3093             :       END IF
    3094             : 
    3095       88002 :    END SUBROUTINE deallocate_pw
    3096             : 
    3097             : ! **************************************************************************************************
    3098             : !> \brief updates virial from first derivative w.r.t. norm_drho
    3099             : !> \param virial_pw ...
    3100             : !> \param drho ...
    3101             : !> \param drho1 ...
    3102             : !> \param deriv_data ...
    3103             : !> \param virial_xc ...
    3104             : ! **************************************************************************************************
    3105         304 :    SUBROUTINE virial_drho_drho1(virial_pw, drho, drho1, deriv_data, virial_xc)
    3106             :       TYPE(pw_r3d_rs_type), INTENT(IN)                          :: virial_pw
    3107             :       TYPE(cp_3d_r_cp_type), DIMENSION(3), INTENT(IN)     :: drho, drho1
    3108             :       REAL(KIND=dp), DIMENSION(:, :, :), INTENT(IN)      :: deriv_data
    3109             :       REAL(KIND=dp), DIMENSION(3, 3), INTENT(INOUT)      :: virial_xc
    3110             : 
    3111             :       INTEGER                                            :: idir, jdir
    3112             :       REAL(KIND=dp)                                      :: tmp
    3113             : 
    3114        1216 :       DO idir = 1, 3
    3115         912 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(drho,idir,virial_pw,deriv_data)
    3116             :          virial_pw%array(:, :, :) = drho(idir)%array(:, :, :)*deriv_data(:, :, :)
    3117             : !$OMP END PARALLEL WORKSHARE
    3118        3952 :          DO jdir = 1, 3
    3119             :             tmp = virial_pw%pw_grid%dvol*accurate_dot_product(virial_pw%array(:, :, :), &
    3120        2736 :                                                               drho1(jdir)%array(:, :, :))
    3121        2736 :             virial_xc(jdir, idir) = virial_xc(jdir, idir) + tmp
    3122        3648 :             virial_xc(idir, jdir) = virial_xc(idir, jdir) + tmp
    3123             :          END DO
    3124             :       END DO
    3125             : 
    3126         304 :    END SUBROUTINE virial_drho_drho1
    3127             : 
    3128             : ! **************************************************************************************************
    3129             : !> \brief Adds virial contribution from second order potential parts
    3130             : !> \param virial_pw ...
    3131             : !> \param drho ...
    3132             : !> \param v_drho ...
    3133             : !> \param virial_xc ...
    3134             : ! **************************************************************************************************
    3135         298 :    SUBROUTINE virial_drho_drho(virial_pw, drho, v_drho, virial_xc)
    3136             :       TYPE(pw_r3d_rs_type), INTENT(IN)                          :: virial_pw
    3137             :       TYPE(cp_3d_r_cp_type), DIMENSION(3), INTENT(IN)     :: drho
    3138             :       TYPE(pw_r3d_rs_type), INTENT(IN)                        :: v_drho
    3139             :       REAL(KIND=dp), DIMENSION(3, 3), INTENT(INOUT)      :: virial_xc
    3140             : 
    3141             :       INTEGER                                            :: idir, jdir
    3142             :       REAL(KIND=dp)                                      :: tmp
    3143             : 
    3144        1192 :       DO idir = 1, 3
    3145         894 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(drho,idir,v_drho,virial_pw)
    3146             :          virial_pw%array(:, :, :) = drho(idir)%array(:, :, :)*v_drho%array(:, :, :)
    3147             : !$OMP END PARALLEL WORKSHARE
    3148        2980 :          DO jdir = 1, idir
    3149             :             tmp = -virial_pw%pw_grid%dvol*accurate_dot_product(virial_pw%array(:, :, :), &
    3150        1788 :                                                                drho(jdir)%array(:, :, :))
    3151        1788 :             virial_xc(jdir, idir) = virial_xc(jdir, idir) + tmp
    3152        2682 :             virial_xc(idir, jdir) = virial_xc(jdir, idir)
    3153             :          END DO
    3154             :       END DO
    3155             : 
    3156         298 :    END SUBROUTINE virial_drho_drho
    3157             : 
    3158             : ! **************************************************************************************************
    3159             : !> \brief ...
    3160             : !> \param rho_r ...
    3161             : !> \param pw_pool ...
    3162             : !> \param virial_xc ...
    3163             : !> \param deriv_data ...
    3164             : ! **************************************************************************************************
    3165         150 :    SUBROUTINE virial_laplace(rho_r, pw_pool, virial_xc, deriv_data)
    3166             :       TYPE(pw_r3d_rs_type), TARGET :: rho_r
    3167             :       TYPE(pw_pool_type), POINTER, INTENT(IN) :: pw_pool
    3168             :       REAL(KIND=dp), DIMENSION(3, 3), INTENT(INOUT) :: virial_xc
    3169             :       REAL(KIND=dp), DIMENSION(:, :, :), INTENT(IN) :: deriv_data
    3170             : 
    3171             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'virial_laplace'
    3172             : 
    3173             :       INTEGER :: handle, idir, jdir
    3174             :       TYPE(pw_r3d_rs_type), POINTER :: virial_pw
    3175             :       TYPE(pw_c1d_gs_type), POINTER :: tmp_g, rho_g
    3176             :       INTEGER, DIMENSION(3) :: my_deriv
    3177             : 
    3178         150 :       CALL timeset(routineN, handle)
    3179             : 
    3180         150 :       NULLIFY (virial_pw, tmp_g, rho_g)
    3181         150 :       ALLOCATE (virial_pw, tmp_g, rho_g)
    3182         150 :       CALL pw_pool%create_pw(virial_pw)
    3183         150 :       CALL pw_pool%create_pw(tmp_g)
    3184         150 :       CALL pw_pool%create_pw(rho_g)
    3185         150 :       CALL pw_zero(virial_pw)
    3186         150 :       CALL pw_transfer(rho_r, rho_g)
    3187         600 :       DO idir = 1, 3
    3188        1500 :          DO jdir = idir, 3
    3189         900 :             CALL pw_copy(rho_g, tmp_g)
    3190             : 
    3191         900 :             my_deriv = 0
    3192         900 :             my_deriv(idir) = 1
    3193         900 :             my_deriv(jdir) = my_deriv(jdir) + 1
    3194             : 
    3195         900 :             CALL pw_derive(tmp_g, my_deriv)
    3196         900 :             CALL pw_transfer(tmp_g, virial_pw)
    3197             :             virial_xc(idir, jdir) = virial_xc(idir, jdir) - 2.0_dp*virial_pw%pw_grid%dvol* &
    3198             :                                     accurate_dot_product(virial_pw%array(:, :, :), &
    3199         900 :                                                          deriv_data(:, :, :))
    3200        1350 :             virial_xc(jdir, idir) = virial_xc(idir, jdir)
    3201             :          END DO
    3202             :       END DO
    3203         150 :       CALL pw_pool%give_back_pw(virial_pw)
    3204         150 :       CALL pw_pool%give_back_pw(tmp_g)
    3205         150 :       CALL pw_pool%give_back_pw(rho_g)
    3206         150 :       DEALLOCATE (virial_pw, tmp_g, rho_g)
    3207             : 
    3208         150 :       CALL timestop(handle)
    3209             : 
    3210         150 :    END SUBROUTINE virial_laplace
    3211             : 
    3212             : ! **************************************************************************************************
    3213             : !> \brief Prepare objects for the calculation of the 2nd derivatives of the density functional.
    3214             : !>      The calculation must then be performed with xc_calc_2nd_deriv.
    3215             : !> \param deriv_set object containing the XC derivatives (out)
    3216             : !> \param rho_set object that will contain the density at which the
    3217             : !>        derivatives were calculated
    3218             : !> \param rho_r the place where you evaluate the derivative
    3219             : !> \param pw_pool the pool for the grids
    3220             : !> \param xc_section which functional should be used and how to calculate it
    3221             : !> \param tau_r kinetic energy density in real space
    3222             : ! **************************************************************************************************
    3223       12114 :    SUBROUTINE xc_prep_2nd_deriv(deriv_set, &
    3224             :                                 rho_set, rho_r, pw_pool, xc_section, tau_r)
    3225             : 
    3226             :       TYPE(xc_derivative_set_type)                       :: deriv_set
    3227             :       TYPE(xc_rho_set_type)                              :: rho_set
    3228             :       TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER               :: rho_r
    3229             :       TYPE(pw_pool_type), POINTER                        :: pw_pool
    3230             :       TYPE(section_vals_type), POINTER                   :: xc_section
    3231             :       TYPE(pw_r3d_rs_type), DIMENSION(:), OPTIONAL, POINTER     :: tau_r
    3232             : 
    3233             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'xc_prep_2nd_deriv'
    3234             : 
    3235             :       INTEGER                                            :: handle, nspins
    3236             :       LOGICAL                                            :: lsd
    3237       12114 :       TYPE(pw_c1d_gs_type), DIMENSION(:), POINTER               :: rho_g
    3238       12114 :       TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: tau
    3239             : 
    3240       12114 :       CALL timeset(routineN, handle)
    3241             : 
    3242       12114 :       CPASSERT(ASSOCIATED(xc_section))
    3243       12114 :       CPASSERT(ASSOCIATED(pw_pool))
    3244             : 
    3245       12114 :       nspins = SIZE(rho_r)
    3246       12114 :       lsd = (nspins /= 1)
    3247             : 
    3248       12114 :       NULLIFY (rho_g, tau)
    3249       12114 :       IF (PRESENT(tau_r)) &
    3250       11452 :          tau => tau_r
    3251             : 
    3252       12114 :       IF (section_get_lval(xc_section, "2ND_DERIV_ANALYTICAL")) THEN
    3253             :          CALL xc_rho_set_and_dset_create(rho_set, deriv_set, 2, &
    3254             :                                          rho_r, rho_g, tau, xc_section, pw_pool, &
    3255       12030 :                                          calc_potential=.TRUE.)
    3256             :       ELSE
    3257             :          CALL xc_rho_set_and_dset_create(rho_set, deriv_set, 1, &
    3258             :                                          rho_r, rho_g, tau, xc_section, pw_pool, &
    3259          84 :                                          calc_potential=.TRUE.)
    3260             :       END IF
    3261             : 
    3262       12114 :       CALL timestop(handle)
    3263             : 
    3264       12114 :    END SUBROUTINE xc_prep_2nd_deriv
    3265             : 
    3266             : ! **************************************************************************************************
    3267             : !> \brief divides derivatives from deriv_set by norm_drho
    3268             : !> \param deriv_set ...
    3269             : !> \param rho_set ...
    3270             : !> \param lsd ...
    3271             : ! **************************************************************************************************
    3272      143461 :    SUBROUTINE divide_by_norm_drho(deriv_set, rho_set, lsd)
    3273             : 
    3274             :       TYPE(xc_derivative_set_type), INTENT(INOUT)        :: deriv_set
    3275             :       TYPE(xc_rho_set_type), INTENT(IN)                  :: rho_set
    3276             :       LOGICAL, INTENT(IN)                                :: lsd
    3277             : 
    3278      143461 :       INTEGER, DIMENSION(:), POINTER                     :: split_desc
    3279             :       INTEGER                                            :: idesc
    3280             :       INTEGER, DIMENSION(2, 3)                           :: bo
    3281             :       REAL(KIND=dp)                                      :: drho_cutoff
    3282      143461 :       REAL(KIND=dp), DIMENSION(:, :, :), POINTER         :: norm_drho, norm_drhoa, norm_drhob
    3283     1721532 :       TYPE(cp_3d_r_cp_type), DIMENSION(3)                 :: drho, drhoa, drhob
    3284             :       TYPE(cp_sll_xc_deriv_type), POINTER                :: pos
    3285             :       TYPE(xc_derivative_type), POINTER                  :: deriv_att
    3286             : 
    3287             : ! check for unknown derivatives and divide by norm_drho where necessary
    3288             : 
    3289     1434610 :       bo = rho_set%local_bounds
    3290             :       CALL xc_rho_set_get(rho_set, drho_cutoff=drho_cutoff, norm_drho=norm_drho, &
    3291             :                           norm_drhoa=norm_drhoa, norm_drhob=norm_drhob, &
    3292      143461 :                           drho=drho, drhoa=drhoa, drhob=drhob, can_return_null=.TRUE.)
    3293             : 
    3294      143461 :       pos => deriv_set%derivs
    3295      608697 :       DO WHILE (cp_sll_xc_deriv_next(pos, el_att=deriv_att))
    3296      465236 :          CALL xc_derivative_get(deriv_att, split_desc=split_desc)
    3297      990700 :          DO idesc = 1, SIZE(split_desc)
    3298      465236 :             SELECT CASE (split_desc(idesc))
    3299             :             CASE (deriv_norm_drho)
    3300      115717 :                IF (ASSOCIATED(norm_drho)) THEN
    3301      115717 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(deriv_att,norm_drho,drho_cutoff)
    3302             :                   deriv_att%deriv_data(:, :, :) = deriv_att%deriv_data(:, :, :)/ &
    3303             :                                                   MAX(norm_drho(:, :, :), drho_cutoff)
    3304             : !$OMP END PARALLEL WORKSHARE
    3305           0 :                ELSE IF (ASSOCIATED(drho(1)%array)) THEN
    3306           0 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(deriv_att,drho,drho_cutoff)
    3307             :                   deriv_att%deriv_data(:, :, :) = deriv_att%deriv_data(:, :, :)/ &
    3308             :                                                   MAX(SQRT(drho(1)%array(:, :, :)**2 + &
    3309             :                                                            drho(2)%array(:, :, :)**2 + &
    3310             :                                                            drho(3)%array(:, :, :)**2), drho_cutoff)
    3311             : !$OMP END PARALLEL WORKSHARE
    3312           0 :                ELSE IF (ASSOCIATED(drhoa(1)%array) .AND. ASSOCIATED(drhob(1)%array)) THEN
    3313           0 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(deriv_att,drhoa,drhob,drho_cutoff)
    3314             :                   deriv_att%deriv_data(:, :, :) = deriv_att%deriv_data(:, :, :)/ &
    3315             :                                                   MAX(SQRT((drhoa(1)%array(:, :, :) + drhob(1)%array(:, :, :))**2 + &
    3316             :                                                            (drhoa(2)%array(:, :, :) + drhob(2)%array(:, :, :))**2 + &
    3317             :                                                            (drhoa(3)%array(:, :, :) + drhob(3)%array(:, :, :))**2), drho_cutoff)
    3318             : !$OMP END PARALLEL WORKSHARE
    3319             :                ELSE
    3320           0 :                   CPABORT("Normalization of derivative requires any of norm_drho, drho or drhoa+drhob!")
    3321             :                END IF
    3322             :             CASE (deriv_norm_drhoa)
    3323       19286 :                IF (ASSOCIATED(norm_drhoa)) THEN
    3324       19286 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(deriv_att,norm_drhoa,drho_cutoff)
    3325             :                   deriv_att%deriv_data(:, :, :) = deriv_att%deriv_data(:, :, :)/ &
    3326             :                                                   MAX(norm_drhoa(:, :, :), drho_cutoff)
    3327             : !$OMP END PARALLEL WORKSHARE
    3328           0 :                ELSE IF (ASSOCIATED(drhoa(1)%array)) THEN
    3329           0 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(deriv_att,drhoa,drho_cutoff)
    3330             :                   deriv_att%deriv_data(:, :, :) = deriv_att%deriv_data(:, :, :)/ &
    3331             :                                                   MAX(SQRT(drhoa(1)%array(:, :, :)**2 + &
    3332             :                                                            drhoa(2)%array(:, :, :)**2 + &
    3333             :                                                            drhoa(3)%array(:, :, :)**2), drho_cutoff)
    3334             : !$OMP END PARALLEL WORKSHARE
    3335             :                ELSE
    3336           0 :                   CPABORT("Normalization of derivative requires any of norm_drhoa or drhoa!")
    3337             :                END IF
    3338             :             CASE (deriv_norm_drhob)
    3339       19282 :                IF (ASSOCIATED(norm_drhob)) THEN
    3340       19282 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(deriv_att,norm_drhob,drho_cutoff)
    3341             :                   deriv_att%deriv_data(:, :, :) = deriv_att%deriv_data(:, :, :)/ &
    3342             :                                                   MAX(norm_drhob(:, :, :), drho_cutoff)
    3343             : !$OMP END PARALLEL WORKSHARE
    3344           0 :                ELSE IF (ASSOCIATED(drhob(1)%array)) THEN
    3345           0 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(deriv_att,drhob,drho_cutoff)
    3346             :                   deriv_att%deriv_data(:, :, :) = deriv_att%deriv_data(:, :, :)/ &
    3347             :                                                   MAX(SQRT(drhob(1)%array(:, :, :)**2 + &
    3348             :                                                            drhob(2)%array(:, :, :)**2 + &
    3349             :                                                            drhob(3)%array(:, :, :)**2), drho_cutoff)
    3350             : !$OMP END PARALLEL WORKSHARE
    3351             :                ELSE
    3352           0 :                   CPABORT("Normalization of derivative requires any of norm_drhob or drhob!")
    3353             :                END IF
    3354             :             CASE (deriv_rho, deriv_tau, deriv_laplace_rho)
    3355      160954 :                IF (lsd) &
    3356           0 :                   CPABORT(TRIM(id_to_desc(split_desc(idesc)))//" not handled in lsd!'")
    3357             :             CASE (deriv_rhoa, deriv_rhob, deriv_tau_a, deriv_tau_b, deriv_laplace_rhoa, deriv_laplace_rhob)
    3358             :             CASE default
    3359      382003 :                CPABORT("Unknown derivative id")
    3360             :             END SELECT
    3361             :          END DO
    3362             :       END DO
    3363             : 
    3364      143461 :    END SUBROUTINE divide_by_norm_drho
    3365             : 
    3366             : ! **************************************************************************************************
    3367             : !> \brief allocates and calculates drho from given spin densities drhoa, drhob
    3368             : !> \param drho ...
    3369             : !> \param drhoa ...
    3370             : !> \param drhob ...
    3371             : ! **************************************************************************************************
    3372       16080 :    SUBROUTINE calc_drho_from_ab(drho, drhoa, drhob)
    3373             :       TYPE(cp_3d_r_cp_type), DIMENSION(3), INTENT(OUT)    :: drho
    3374             :       TYPE(cp_3d_r_cp_type), DIMENSION(3), INTENT(IN)     :: drhoa, drhob
    3375             : 
    3376             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'calc_drho_from_ab'
    3377             : 
    3378             :       INTEGER                                            :: handle, idir
    3379             : 
    3380        4020 :       CALL timeset(routineN, handle)
    3381             : 
    3382       16080 :       DO idir = 1, 3
    3383       12060 :          NULLIFY (drho(idir)%array)
    3384             :          ALLOCATE (drho(idir)%array(LBOUND(drhoa(1)%array, 1):UBOUND(drhoa(1)%array, 1), &
    3385             :                                     LBOUND(drhoa(1)%array, 2):UBOUND(drhoa(1)%array, 2), &
    3386      144720 :                                     LBOUND(drhoa(1)%array, 3):UBOUND(drhoa(1)%array, 3)))
    3387       16080 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(drho,drhoa,drhob,idir)
    3388             :          drho(idir)%array(:, :, :) = drhoa(idir)%array(:, :, :) + drhob(idir)%array(:, :, :)
    3389             : !$OMP END PARALLEL WORKSHARE
    3390             :       END DO
    3391             : 
    3392        4020 :       CALL timestop(handle)
    3393             : 
    3394        4020 :    END SUBROUTINE calc_drho_from_ab
    3395             : 
    3396             : ! **************************************************************************************************
    3397             : !> \brief allocates and calculates dot products of two density gradients
    3398             : !> \param dr1dr ...
    3399             : !> \param drho ...
    3400             : !> \param drho1 ...
    3401             : ! **************************************************************************************************
    3402       22276 :    SUBROUTINE prepare_dr1dr(dr1dr, drho, drho1)
    3403             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :), &
    3404             :          INTENT(OUT)                                     :: dr1dr
    3405             :       TYPE(cp_3d_r_cp_type), DIMENSION(3), INTENT(IN)     :: drho, drho1
    3406             : 
    3407             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'prepare_dr1dr'
    3408             : 
    3409             :       INTEGER                                            :: handle, idir
    3410             : 
    3411       22276 :       CALL timeset(routineN, handle)
    3412             : 
    3413           0 :       ALLOCATE (dr1dr(LBOUND(drho(1)%array, 1):UBOUND(drho(1)%array, 1), &
    3414             :                       LBOUND(drho(1)%array, 2):UBOUND(drho(1)%array, 2), &
    3415      267312 :                       LBOUND(drho(1)%array, 3):UBOUND(drho(1)%array, 3)))
    3416             : 
    3417       22276 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(dr1dr,drho,drho1)
    3418             :       dr1dr(:, :, :) = drho(1)%array(:, :, :)*drho1(1)%array(:, :, :)
    3419             : !$OMP END PARALLEL WORKSHARE
    3420       66828 :       DO idir = 2, 3
    3421       66828 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(dr1dr,drho,drho1,idir)
    3422             :          dr1dr(:, :, :) = dr1dr(:, :, :) + drho(idir)%array(:, :, :)*drho1(idir)%array(:, :, :)
    3423             : !$OMP END PARALLEL WORKSHARE
    3424             :       END DO
    3425             : 
    3426       22276 :       CALL timestop(handle)
    3427             : 
    3428       22276 :    END SUBROUTINE prepare_dr1dr
    3429             : 
    3430             : ! **************************************************************************************************
    3431             : !> \brief allocates and calculates dot product of two densities for triplets
    3432             : !> \param dr1dr ...
    3433             : !> \param drhoa ...
    3434             : !> \param drhob ...
    3435             : !> \param drho1a ...
    3436             : !> \param drho1b ...
    3437             : !> \param fac ...
    3438             : ! **************************************************************************************************
    3439         710 :    SUBROUTINE prepare_dr1dr_ab(dr1dr, drhoa, drhob, drho1a, drho1b, fac)
    3440             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :), &
    3441             :          INTENT(OUT)                                     :: dr1dr
    3442             :       TYPE(cp_3d_r_cp_type), DIMENSION(3), INTENT(IN)    :: drhoa, drhob, drho1a, drho1b
    3443             :       REAL(KIND=dp), INTENT(IN)                          :: fac
    3444             : 
    3445             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'prepare_dr1dr_ab'
    3446             : 
    3447             :       INTEGER                                            :: handle, idir
    3448             : 
    3449         710 :       CALL timeset(routineN, handle)
    3450             : 
    3451           0 :       ALLOCATE (dr1dr(LBOUND(drhoa(1)%array, 1):UBOUND(drhoa(1)%array, 1), &
    3452             :                       LBOUND(drhoa(1)%array, 2):UBOUND(drhoa(1)%array, 2), &
    3453        8520 :                       LBOUND(drhoa(1)%array, 3):UBOUND(drhoa(1)%array, 3)))
    3454             : 
    3455         710 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(fac,dr1dr,drho1a,drho1b,drhoa,drhob)
    3456             :       dr1dr(:, :, :) = drhoa(1)%array(:, :, :)*(drho1a(1)%array(:, :, :) + &
    3457             :                                                 fac*drho1b(1)%array(:, :, :)) + &
    3458             :                        drhob(1)%array(:, :, :)*(fac*drho1a(1)%array(:, :, :) + &
    3459             :                                                 drho1b(1)%array(:, :, :))
    3460             : !$OMP END PARALLEL WORKSHARE
    3461        2130 :       DO idir = 2, 3
    3462        2130 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(fac,dr1dr,drho1a,drho1b,drhoa,drhob,idir)
    3463             :          dr1dr(:, :, :) = dr1dr(:, :, :) + &
    3464             :                           drhoa(idir)%array(:, :, :)*(drho1a(idir)%array(:, :, :) + &
    3465             :                                                       fac*drho1b(idir)%array(:, :, :)) + &
    3466             :                           drhob(idir)%array(:, :, :)*(fac*drho1a(idir)%array(:, :, :) + &
    3467             :                                                       drho1b(idir)%array(:, :, :))
    3468             : !$OMP END PARALLEL WORKSHARE
    3469             :       END DO
    3470             : 
    3471         710 :       CALL timestop(handle)
    3472             : 
    3473         710 :    END SUBROUTINE prepare_dr1dr_ab
    3474             : 
    3475             : ! **************************************************************************************************
    3476             : !> \brief checks for gradients
    3477             : !> \param deriv_set ...
    3478             : !> \param lsd ...
    3479             : !> \param gradient_f ...
    3480             : !> \param tau_f ...
    3481             : !> \param laplace_f ...
    3482             : ! **************************************************************************************************
    3483      141331 :    SUBROUTINE check_for_derivatives(deriv_set, lsd, rho_f, gradient_f, tau_f, laplace_f)
    3484             :       TYPE(xc_derivative_set_type), INTENT(IN)           :: deriv_set
    3485             :       LOGICAL, INTENT(IN)                                :: lsd
    3486             :       LOGICAL, INTENT(OUT)                               :: rho_f, gradient_f, tau_f, laplace_f
    3487             : 
    3488             :       CHARACTER(len=*), PARAMETER :: routineN = 'check_for_derivatives'
    3489             : 
    3490             :       INTEGER                                            :: handle, iorder, order
    3491      141331 :       INTEGER, DIMENSION(:), POINTER                     :: split_desc
    3492             :       TYPE(cp_sll_xc_deriv_type), POINTER                :: pos
    3493             :       TYPE(xc_derivative_type), POINTER                  :: deriv_att
    3494             : 
    3495      141331 :       CALL timeset(routineN, handle)
    3496             : 
    3497      141331 :       rho_f = .FALSE.
    3498      141331 :       gradient_f = .FALSE.
    3499      141331 :       tau_f = .FALSE.
    3500      141331 :       laplace_f = .FALSE.
    3501             :       ! check for unknown derivatives
    3502      141331 :       pos => deriv_set%derivs
    3503      642071 :       DO WHILE (cp_sll_xc_deriv_next(pos, el_att=deriv_att))
    3504             :          CALL xc_derivative_get(deriv_att, order=order, &
    3505      500740 :                                 split_desc=split_desc)
    3506      642071 :          IF (lsd) THEN
    3507      301805 :             DO iorder = 1, size(split_desc)
    3508      150653 :                SELECT CASE (split_desc(iorder))
    3509             :                CASE (deriv_rhoa, deriv_rhob)
    3510       78056 :                   rho_f = .TRUE.
    3511             :                CASE (deriv_norm_drho, deriv_norm_drhoa, deriv_norm_drhob)
    3512       69024 :                   gradient_f = .TRUE.
    3513             :                CASE (deriv_tau_a, deriv_tau_b)
    3514        2760 :                   tau_f = .TRUE.
    3515             :                CASE (deriv_laplace_rhoa, deriv_laplace_rhob)
    3516        1312 :                   laplace_f = .TRUE.
    3517             :                CASE (deriv_rho, deriv_tau, deriv_laplace_rho)
    3518           0 :                   CPABORT("Derivative not handled in lsd!")
    3519             :                CASE default
    3520      151152 :                   CPABORT("Unknown derivative id")
    3521             :                END SELECT
    3522             :             END DO
    3523             :          ELSE
    3524      647552 :             DO iorder = 1, size(split_desc)
    3525      350087 :                SELECT CASE (split_desc(iorder))
    3526             :                CASE (deriv_rho)
    3527      176158 :                   rho_f = .TRUE.
    3528             :                CASE (deriv_tau)
    3529        4948 :                   tau_f = .TRUE.
    3530             :                CASE (deriv_norm_drho)
    3531      114921 :                   gradient_f = .TRUE.
    3532             :                CASE (deriv_laplace_rho)
    3533        1438 :                   laplace_f = .TRUE.
    3534             :                CASE default
    3535      297465 :                   CPABORT("Unknown derivative id")
    3536             :                END SELECT
    3537             :             END DO
    3538             :          END IF
    3539             :       END DO
    3540             : 
    3541      141331 :       CALL timestop(handle)
    3542             : 
    3543      141331 :    END SUBROUTINE check_for_derivatives
    3544             : 
    3545             : END MODULE xc

Generated by: LCOV version 1.15