LCOV - code coverage report
Current view: top level - src/xc - xc.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:9ccafda) Lines: 90.0 % 1346 1211
Test Date: 2026-10-15 00:55:44 Functions: 96.8 % 31 30

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

Generated by: LCOV version 2.0-1