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

Generated by: LCOV version 2.0-1