LCOV - code coverage report
Current view: top level - src/xc - xc.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:70636b1) Lines: 78.9 % 1207 952
Test Date: 2026-02-11 07:00:35 Functions: 93.5 % 31 29

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

Generated by: LCOV version 2.0-1