LCOV - code coverage report
Current view: top level - src - xas_tdp_atom.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:dc8eeee) Lines: 1090 1133 96.2 %
Date: 2025-05-15 08:34:30 Functions: 19 20 95.0 %

          Line data    Source code
       1             : !--------------------------------------------------------------------------------------------------!
       2             : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3             : !   Copyright 2000-2025 CP2K developers group <https://cp2k.org>                                   !
       4             : !                                                                                                  !
       5             : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6             : !--------------------------------------------------------------------------------------------------!
       7             : 
       8             : ! **************************************************************************************************
       9             : !> \brief This module deals with all the integrals done on local atomic grids in xas_tdp. This is
      10             : !>        mostly used to compute the xc kernel matrix elements wrt two RI basis elements (centered
      11             : !>        on the same excited atom) <P|fxc(r)|Q>, where the kernel fxc is purely a function of the
      12             : !>        ground state density and r. This is also used to compute the SOC matrix elements in the
      13             : !>        orbital basis
      14             : ! **************************************************************************************************
      15             : MODULE xas_tdp_atom
      16             :    USE ai_contraction_sphi,             ONLY: ab_contract
      17             :    USE atom_operators,                  ONLY: calculate_model_potential
      18             :    USE basis_set_types,                 ONLY: get_gto_basis_set,&
      19             :                                               gto_basis_set_p_type,&
      20             :                                               gto_basis_set_type
      21             :    USE cell_types,                      ONLY: cell_type,&
      22             :                                               pbc
      23             :    USE cp_array_utils,                  ONLY: cp_1d_i_p_type,&
      24             :                                               cp_1d_r_p_type,&
      25             :                                               cp_2d_r_p_type,&
      26             :                                               cp_3d_r_p_type
      27             :    USE cp_blacs_env,                    ONLY: cp_blacs_env_type
      28             :    USE cp_control_types,                ONLY: dft_control_type,&
      29             :                                               qs_control_type
      30             :    USE cp_dbcsr_api,                    ONLY: &
      31             :         dbcsr_copy, dbcsr_create, dbcsr_distribution_get, dbcsr_distribution_new, &
      32             :         dbcsr_distribution_release, dbcsr_distribution_type, dbcsr_filter, dbcsr_finalize, &
      33             :         dbcsr_get_block_p, dbcsr_get_stored_coordinates, dbcsr_iterator_blocks_left, &
      34             :         dbcsr_iterator_next_block, dbcsr_iterator_readonly_start, dbcsr_iterator_start, &
      35             :         dbcsr_iterator_stop, dbcsr_iterator_type, dbcsr_p_type, dbcsr_put_block, dbcsr_release, &
      36             :         dbcsr_replicate_all, dbcsr_set, dbcsr_type, dbcsr_type_antisymmetric, &
      37             :         dbcsr_type_no_symmetry, dbcsr_type_symmetric
      38             :    USE cp_dbcsr_cholesky,               ONLY: cp_dbcsr_cholesky_decompose,&
      39             :                                               cp_dbcsr_cholesky_invert
      40             :    USE cp_dbcsr_operations,             ONLY: dbcsr_deallocate_matrix_set
      41             :    USE cp_log_handling,                 ONLY: cp_logger_get_default_io_unit
      42             :    USE dbt_api,                         ONLY: dbt_destroy,&
      43             :                                               dbt_get_block,&
      44             :                                               dbt_iterator_blocks_left,&
      45             :                                               dbt_iterator_next_block,&
      46             :                                               dbt_iterator_start,&
      47             :                                               dbt_iterator_stop,&
      48             :                                               dbt_iterator_type,&
      49             :                                               dbt_type
      50             :    USE input_constants,                 ONLY: do_potential_id
      51             :    USE input_section_types,             ONLY: section_vals_get_subs_vals,&
      52             :                                               section_vals_type
      53             :    USE kinds,                           ONLY: default_string_length,&
      54             :                                               dp
      55             :    USE lebedev,                         ONLY: deallocate_lebedev_grids,&
      56             :                                               get_number_of_lebedev_grid,&
      57             :                                               init_lebedev_grids,&
      58             :                                               lebedev_grid
      59             :    USE libint_2c_3c,                    ONLY: libint_potential_type
      60             :    USE mathlib,                         ONLY: get_diag,&
      61             :                                               invmat_symm
      62             :    USE memory_utilities,                ONLY: reallocate
      63             :    USE message_passing,                 ONLY: mp_comm_type,&
      64             :                                               mp_para_env_type,&
      65             :                                               mp_request_type,&
      66             :                                               mp_waitall
      67             :    USE orbital_pointers,                ONLY: indco,&
      68             :                                               indso,&
      69             :                                               nco,&
      70             :                                               ncoset,&
      71             :                                               nso,&
      72             :                                               nsoset
      73             :    USE orbital_transformation_matrices, ONLY: orbtramat
      74             :    USE particle_methods,                ONLY: get_particle_set
      75             :    USE particle_types,                  ONLY: particle_type
      76             :    USE physcon,                         ONLY: c_light_au
      77             :    USE qs_environment_types,            ONLY: get_qs_env,&
      78             :                                               qs_environment_type
      79             :    USE qs_grid_atom,                    ONLY: allocate_grid_atom,&
      80             :                                               create_grid_atom,&
      81             :                                               grid_atom_type
      82             :    USE qs_harmonics_atom,               ONLY: allocate_harmonics_atom,&
      83             :                                               create_harmonics_atom,&
      84             :                                               get_maxl_CG,&
      85             :                                               get_none0_cg_list,&
      86             :                                               harmonics_atom_type
      87             :    USE qs_integral_utils,               ONLY: basis_set_list_setup
      88             :    USE qs_kind_types,                   ONLY: get_qs_kind,&
      89             :                                               get_qs_kind_set,&
      90             :                                               qs_kind_type
      91             :    USE qs_neighbor_list_types,          ONLY: neighbor_list_set_p_type,&
      92             :                                               release_neighbor_list_sets
      93             :    USE qs_overlap,                      ONLY: build_overlap_matrix_simple
      94             :    USE qs_rho_types,                    ONLY: qs_rho_get,&
      95             :                                               qs_rho_type
      96             :    USE qs_tddfpt2_soc_types,            ONLY: soc_atom_env_type
      97             :    USE spherical_harmonics,             ONLY: clebsch_gordon,&
      98             :                                               clebsch_gordon_deallocate,&
      99             :                                               clebsch_gordon_init
     100             :    USE util,                            ONLY: get_limit,&
     101             :                                               sort_unique
     102             :    USE xas_tdp_integrals,               ONLY: build_xas_tdp_3c_nl,&
     103             :                                               build_xas_tdp_ovlp_nl,&
     104             :                                               create_pqX_tensor,&
     105             :                                               fill_pqx_tensor
     106             :    USE xas_tdp_types,                   ONLY: batch_info_type,&
     107             :                                               get_proc_batch_sizes,&
     108             :                                               release_batch_info,&
     109             :                                               xas_atom_env_type,&
     110             :                                               xas_tdp_control_type,&
     111             :                                               xas_tdp_env_type
     112             :    USE xc,                              ONLY: divide_by_norm_drho
     113             :    USE xc_atom,                         ONLY: xc_rho_set_atom_update
     114             :    USE xc_derivative_desc,              ONLY: deriv_norm_drho,&
     115             :                                               deriv_norm_drhoa,&
     116             :                                               deriv_norm_drhob,&
     117             :                                               deriv_rhoa,&
     118             :                                               deriv_rhob
     119             :    USE xc_derivative_set_types,         ONLY: xc_derivative_set_type,&
     120             :                                               xc_dset_create,&
     121             :                                               xc_dset_get_derivative,&
     122             :                                               xc_dset_release
     123             :    USE xc_derivative_types,             ONLY: xc_derivative_get,&
     124             :                                               xc_derivative_type
     125             :    USE xc_derivatives,                  ONLY: xc_functionals_eval,&
     126             :                                               xc_functionals_get_needs
     127             :    USE xc_rho_cflags_types,             ONLY: xc_rho_cflags_type
     128             :    USE xc_rho_set_types,                ONLY: xc_rho_set_create,&
     129             :                                               xc_rho_set_release,&
     130             :                                               xc_rho_set_type
     131             : 
     132             : !$ USE OMP_LIB, ONLY: omp_get_max_threads, omp_get_thread_num
     133             : #include "./base/base_uses.f90"
     134             : 
     135             :    IMPLICIT NONE
     136             : 
     137             :    PRIVATE
     138             : 
     139             :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'xas_tdp_atom'
     140             : 
     141             :    PUBLIC :: init_xas_atom_env, &
     142             :              integrate_fxc_atoms, &
     143             :              integrate_soc_atoms, &
     144             :              calculate_density_coeffs, &
     145             :              compute_sphi_so, &
     146             :              truncate_radial_grid, &
     147             :              init_xas_atom_grid_harmo
     148             : 
     149             : CONTAINS
     150             : 
     151             : ! **************************************************************************************************
     152             : !> \brief Initializes a xas_atom_env type given the qs_enxas_atom_env, qs_envv
     153             : !> \param xas_atom_env the xas_atom_env to initialize
     154             : !> \param xas_tdp_env ...
     155             : !> \param xas_tdp_control ...
     156             : !> \param qs_env ...
     157             : !> \param ltddfpt ...
     158             : ! **************************************************************************************************
     159          48 :    SUBROUTINE init_xas_atom_env(xas_atom_env, xas_tdp_env, xas_tdp_control, qs_env, ltddfpt)
     160             : 
     161             :       TYPE(xas_atom_env_type), POINTER                   :: xas_atom_env
     162             :       TYPE(xas_tdp_env_type), POINTER                    :: xas_tdp_env
     163             :       TYPE(xas_tdp_control_type), POINTER                :: xas_tdp_control
     164             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     165             :       LOGICAL, OPTIONAL                                  :: ltddfpt
     166             : 
     167             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'init_xas_atom_env'
     168             : 
     169             :       INTEGER                                            :: handle, ikind, natom, nex_atoms, &
     170             :                                                             nex_kinds, nkind, nspins
     171             :       LOGICAL                                            :: do_xc
     172          48 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     173          48 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     174             : 
     175          48 :       NULLIFY (qs_kind_set, particle_set)
     176             : 
     177          48 :       CALL timeset(routineN, handle)
     178             : 
     179             : !  Initializing the type
     180          48 :       CALL get_qs_env(qs_env, qs_kind_set=qs_kind_set, natom=natom, particle_set=particle_set)
     181             : 
     182          48 :       nkind = SIZE(qs_kind_set)
     183          48 :       nex_kinds = xas_tdp_env%nex_kinds
     184          48 :       nex_atoms = xas_tdp_env%nex_atoms
     185          48 :       do_xc = xas_tdp_control%do_xc
     186          48 :       IF (PRESENT(ltddfpt)) THEN
     187           0 :          IF (ltddfpt) do_xc = .FALSE.
     188             :       END IF
     189          48 :       nspins = 1; IF (xas_tdp_control%do_uks .OR. xas_tdp_control%do_roks) nspins = 2
     190             : 
     191          48 :       xas_atom_env%nspins = nspins
     192          48 :       xas_atom_env%ri_radius = xas_tdp_control%ri_radius
     193         218 :       ALLOCATE (xas_atom_env%grid_atom_set(nkind))
     194         218 :       ALLOCATE (xas_atom_env%harmonics_atom_set(nkind))
     195         218 :       ALLOCATE (xas_atom_env%ri_sphi_so(nkind))
     196         218 :       ALLOCATE (xas_atom_env%orb_sphi_so(nkind))
     197          48 :       IF (do_xc) THEN
     198         174 :          ALLOCATE (xas_atom_env%gr(nkind))
     199         174 :          ALLOCATE (xas_atom_env%ga(nkind))
     200         174 :          ALLOCATE (xas_atom_env%dgr1(nkind))
     201         174 :          ALLOCATE (xas_atom_env%dgr2(nkind))
     202         174 :          ALLOCATE (xas_atom_env%dga1(nkind))
     203         174 :          ALLOCATE (xas_atom_env%dga2(nkind))
     204             :       END IF
     205             : 
     206          48 :       xas_atom_env%excited_atoms => xas_tdp_env%ex_atom_indices
     207          48 :       xas_atom_env%excited_kinds => xas_tdp_env%ex_kind_indices
     208             : 
     209             : !  Allocate and initialize the atomic grids and harmonics
     210          48 :       CALL init_xas_atom_grid_harmo(xas_atom_env, xas_tdp_control%grid_info, do_xc, qs_env)
     211             : 
     212             : !  Compute the contraction coefficients for spherical orbitals
     213         122 :       DO ikind = 1, nkind
     214          74 :          NULLIFY (xas_atom_env%orb_sphi_so(ikind)%array, xas_atom_env%ri_sphi_so(ikind)%array)
     215          74 :          CALL compute_sphi_so(ikind, "ORB", xas_atom_env%orb_sphi_so(ikind)%array, qs_env)
     216         150 :          IF (ANY(xas_atom_env%excited_kinds == ikind)) THEN
     217          52 :             CALL compute_sphi_so(ikind, "RI_XAS", xas_atom_env%ri_sphi_so(ikind)%array, qs_env)
     218             :          END IF
     219             :       END DO !ikind
     220             : 
     221             : !  Compute the coefficients to expand the density in the RI_XAS basis, if requested
     222          48 :       IF (do_xc .AND. (.NOT. xas_tdp_control%xps_only)) THEN
     223          38 :          CALL calculate_density_coeffs(xas_atom_env=xas_atom_env, qs_env=qs_env)
     224             :       END IF
     225             : 
     226          48 :       CALL timestop(handle)
     227             : 
     228          48 :    END SUBROUTINE init_xas_atom_env
     229             : 
     230             : ! **************************************************************************************************
     231             : !> \brief Initializes the atomic grids and harmonics for the RI atomic calculations
     232             : !> \param xas_atom_env ...
     233             : !> \param grid_info ...
     234             : !> \param do_xc Whether the xc kernel will ne computed on the atomic grids. If not, the harmonics
     235             : !>        are built for the orbital basis for all kinds.
     236             : !> \param qs_env ...
     237             : !> \note Largely inspired by init_rho_atom subroutine
     238             : ! **************************************************************************************************
     239          48 :    SUBROUTINE init_xas_atom_grid_harmo(xas_atom_env, grid_info, do_xc, qs_env)
     240             : 
     241             :       TYPE(xas_atom_env_type), POINTER                   :: xas_atom_env
     242             :       CHARACTER(len=default_string_length), &
     243             :          DIMENSION(:, :), POINTER                        :: grid_info
     244             :       LOGICAL, INTENT(IN)                                :: do_xc
     245             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     246             : 
     247             :       CHARACTER(LEN=default_string_length)               :: kind_name
     248             :       INTEGER :: igrid, ikind, il, iso, iso1, iso2, l1, l1l2, l2, la, lc1, lc2, lcleb, ll, llmax, &
     249             :          lp, m1, m2, max_s_harm, max_s_set, maxl, maxlgto, maxs, mm, mp, na, nr, quadrature, stat
     250             :       REAL(dp)                                           :: kind_radius
     251          48 :       REAL(dp), ALLOCATABLE, DIMENSION(:, :)             :: rga
     252          48 :       REAL(dp), DIMENSION(:, :, :), POINTER              :: my_CG
     253             :       TYPE(dft_control_type), POINTER                    :: dft_control
     254             :       TYPE(grid_atom_type), POINTER                      :: grid_atom
     255             :       TYPE(gto_basis_set_type), POINTER                  :: tmp_basis
     256             :       TYPE(harmonics_atom_type), POINTER                 :: harmonics
     257             :       TYPE(qs_control_type), POINTER                     :: qs_control
     258          48 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     259             : 
     260          48 :       NULLIFY (my_CG, qs_kind_set, tmp_basis, grid_atom, harmonics, qs_control, dft_control)
     261             : 
     262             : !  Initialization of some integer for the CG coeff generation
     263          48 :       CALL get_qs_env(qs_env, qs_kind_set=qs_kind_set, dft_control=dft_control)
     264          48 :       IF (do_xc) THEN
     265          38 :          CALL get_qs_kind_set(qs_kind_set, maxlgto=maxlgto, basis_type="RI_XAS")
     266             :       ELSE
     267          10 :          CALL get_qs_kind_set(qs_kind_set, maxlgto=maxlgto, basis_type="ORB")
     268             :       END IF
     269          48 :       qs_control => dft_control%qs_control
     270             : 
     271             :       !maximum expansion
     272          48 :       llmax = 2*maxlgto
     273          48 :       max_s_harm = nsoset(llmax)
     274          48 :       max_s_set = nsoset(maxlgto)
     275          48 :       lcleb = llmax
     276             : 
     277             : !  Allocate and compute the CG coeffs (copied from init_rho_atom)
     278          48 :       CALL clebsch_gordon_init(lcleb)
     279          48 :       CALL reallocate(my_CG, 1, max_s_set, 1, max_s_set, 1, max_s_harm)
     280             : 
     281         144 :       ALLOCATE (rga(lcleb, 2))
     282         222 :       DO lc1 = 0, maxlgto
     283         888 :          DO iso1 = nsoset(lc1 - 1) + 1, nsoset(lc1)
     284         666 :             l1 = indso(1, iso1)
     285         666 :             m1 = indso(2, iso1)
     286        3558 :             DO lc2 = 0, maxlgto
     287       15282 :                DO iso2 = nsoset(lc2 - 1) + 1, nsoset(lc2)
     288       11898 :                   l2 = indso(1, iso2)
     289       11898 :                   m2 = indso(2, iso2)
     290       11898 :                   CALL clebsch_gordon(l1, m1, l2, m2, rga)
     291       11898 :                   IF (l1 + l2 > llmax) THEN
     292             :                      l1l2 = llmax
     293             :                   ELSE
     294             :                      l1l2 = l1 + l2
     295             :                   END IF
     296       11898 :                   mp = m1 + m2
     297       11898 :                   mm = m1 - m2
     298       11898 :                   IF (m1*m2 < 0 .OR. (m1*m2 == 0 .AND. (m1 < 0 .OR. m2 < 0))) THEN
     299        5616 :                      mp = -ABS(mp)
     300        5616 :                      mm = -ABS(mm)
     301             :                   ELSE
     302        6282 :                      mp = ABS(mp)
     303        6282 :                      mm = ABS(mm)
     304             :                   END IF
     305       54540 :                   DO lp = MOD(l1 + l2, 2), l1l2, 2
     306       39924 :                      il = lp/2 + 1
     307       39924 :                      IF (ABS(mp) <= lp) THEN
     308       27356 :                      IF (mp >= 0) THEN
     309       15864 :                         iso = nsoset(lp - 1) + lp + 1 + mp
     310             :                      ELSE
     311       11492 :                         iso = nsoset(lp - 1) + lp + 1 - ABS(mp)
     312             :                      END IF
     313       27356 :                      my_CG(iso1, iso2, iso) = rga(il, 1)
     314             :                      END IF
     315       51822 :                      IF (mp /= mm .AND. ABS(mm) <= lp) THEN
     316       17464 :                      IF (mm >= 0) THEN
     317       11304 :                         iso = nsoset(lp - 1) + lp + 1 + mm
     318             :                      ELSE
     319        6160 :                         iso = nsoset(lp - 1) + lp + 1 - ABS(mm)
     320             :                      END IF
     321       17464 :                      my_CG(iso1, iso2, iso) = rga(il, 2)
     322             :                      END IF
     323             :                   END DO
     324             :                END DO ! iso2
     325             :             END DO ! lc2
     326             :          END DO ! iso1
     327             :       END DO ! lc1
     328          48 :       DEALLOCATE (rga)
     329          48 :       CALL clebsch_gordon_deallocate()
     330             : 
     331             : !  Create the Lebedev grids and compute the spherical harmonics
     332          48 :       CALL init_lebedev_grids()
     333          48 :       quadrature = qs_control%gapw_control%quadrature
     334             : 
     335         122 :       DO ikind = 1, SIZE(xas_atom_env%grid_atom_set)
     336             : 
     337             : !        Allocate the grid and the harmonics for this kind
     338          74 :          NULLIFY (xas_atom_env%grid_atom_set(ikind)%grid_atom)
     339          74 :          NULLIFY (xas_atom_env%harmonics_atom_set(ikind)%harmonics_atom)
     340          74 :          CALL allocate_grid_atom(xas_atom_env%grid_atom_set(ikind)%grid_atom)
     341          74 :          CALL allocate_harmonics_atom(xas_atom_env%harmonics_atom_set(ikind)%harmonics_atom)
     342             : 
     343          74 :          NULLIFY (grid_atom, harmonics)
     344          74 :          grid_atom => xas_atom_env%grid_atom_set(ikind)%grid_atom
     345          74 :          harmonics => xas_atom_env%harmonics_atom_set(ikind)%harmonics_atom
     346             : 
     347             : !        Initialize some integers
     348          74 :          CALL get_qs_kind(qs_kind_set(ikind), ngrid_rad=nr, ngrid_ang=na, name=kind_name)
     349             : 
     350             :          !take the grid dimension given as input, if none, take the GAPW ones above
     351         222 :          IF (ANY(grid_info == kind_name)) THEN
     352          50 :             DO igrid = 1, SIZE(grid_info, 1)
     353          50 :                IF (grid_info(igrid, 1) == kind_name) THEN
     354             : 
     355             :                   !hack to convert string into integer
     356          46 :                   READ (grid_info(igrid, 2), *, iostat=stat) na
     357          46 :                   IF (stat .NE. 0) CPABORT("The 'na' value for the GRID keyword must be an integer")
     358          46 :                   READ (grid_info(igrid, 3), *, iostat=stat) nr
     359          46 :                   IF (stat .NE. 0) CPABORT("The 'nr' value for the GRID keyword must be an integer")
     360             :                   EXIT
     361             :                END IF
     362             :             END DO
     363          52 :          ELSE IF (do_xc .AND. ANY(xas_atom_env%excited_kinds == ikind)) THEN
     364             :             !need good integration grids for the xc kernel, but taking the default GAPW grid
     365           0 :             CPWARN("The default (and possibly small) GAPW grid is being used for one excited KIND")
     366             :          END IF
     367             : 
     368          74 :          ll = get_number_of_lebedev_grid(n=na)
     369          74 :          na = lebedev_grid(ll)%n
     370          74 :          la = lebedev_grid(ll)%l
     371          74 :          grid_atom%ng_sphere = na
     372          74 :          grid_atom%nr = nr
     373             : 
     374             : !        If this is an excited kind, create the harmonics with the RI_XAS basis, otherwise the ORB
     375         102 :          IF (ANY(xas_atom_env%excited_kinds == ikind) .AND. do_xc) THEN
     376          42 :             CALL get_qs_kind(qs_kind_set(ikind), basis_set=tmp_basis, basis_type="RI_XAS")
     377             :          ELSE
     378          32 :             CALL get_qs_kind(qs_kind_set(ikind), basis_set=tmp_basis, basis_type="ORB")
     379             :          END IF
     380          74 :          CALL get_gto_basis_set(gto_basis_set=tmp_basis, maxl=maxl, kind_radius=kind_radius)
     381             : 
     382          74 :          CALL create_grid_atom(grid_atom, nr, na, llmax, ll, quadrature)
     383          74 :          CALL truncate_radial_grid(grid_atom, kind_radius)
     384             : 
     385          74 :          maxs = nsoset(maxl)
     386             :          CALL create_harmonics_atom(harmonics, &
     387             :                                     my_CG, na, llmax, maxs, max_s_harm, ll, grid_atom%wa, &
     388          74 :                                     grid_atom%azi, grid_atom%pol)
     389         270 :          CALL get_maxl_CG(harmonics, tmp_basis, llmax, max_s_harm)
     390             :       END DO
     391             : 
     392          48 :       CALL deallocate_lebedev_grids()
     393          48 :       DEALLOCATE (my_CG)
     394             : 
     395          48 :    END SUBROUTINE init_xas_atom_grid_harmo
     396             : 
     397             : ! **************************************************************************************************
     398             : !> \brief Reduces the radial extension of an atomic grid such that it only covers a given radius
     399             : !> \param grid_atom the atomic grid from which we truncate the radial part
     400             : !> \param max_radius the maximal radial extension of the resulting grid
     401             : !> \note Since the RI density used for <P|fxc|Q> is only of quality close to the atom, and the
     402             : !>       integrand only non-zero within the radius of the gaussian P,Q. One can reduce the grid
     403             : !>       extansion to the largest radius of the RI basis set
     404             : ! **************************************************************************************************
     405          82 :    SUBROUTINE truncate_radial_grid(grid_atom, max_radius)
     406             : 
     407             :       TYPE(grid_atom_type), POINTER                      :: grid_atom
     408             :       REAL(dp), INTENT(IN)                               :: max_radius
     409             : 
     410             :       INTEGER                                            :: first_ir, ir, llmax_p1, na, new_nr, nr
     411             : 
     412          82 :       nr = grid_atom%nr
     413          82 :       na = grid_atom%ng_sphere
     414          82 :       llmax_p1 = SIZE(grid_atom%rad2l, 2) - 1
     415             : 
     416             : !     Find the index corresponding to the limiting radius (small ir => large radius)
     417        2076 :       DO ir = 1, nr
     418        2076 :          IF (grid_atom%rad(ir) < max_radius) THEN
     419             :             first_ir = ir
     420             :             EXIT
     421             :          END IF
     422             :       END DO
     423          82 :       new_nr = nr - first_ir + 1
     424             : 
     425             : !     Reallcoate everything that depends on r
     426          82 :       grid_atom%nr = new_nr
     427             : 
     428       15216 :       grid_atom%rad(1:new_nr) = grid_atom%rad(first_ir:nr)
     429       15216 :       grid_atom%rad2(1:new_nr) = grid_atom%rad2(first_ir:nr)
     430       15216 :       grid_atom%wr(1:new_nr) = grid_atom%wr(first_ir:nr)
     431     2372648 :       grid_atom%weight(:, 1:new_nr) = grid_atom%weight(:, first_ir:nr)
     432      114340 :       grid_atom%rad2l(1:new_nr, :) = grid_atom%rad2l(first_ir:nr, :)
     433      114340 :       grid_atom%oorad2l(1:new_nr, :) = grid_atom%oorad2l(first_ir:nr, :)
     434             : 
     435          82 :       CALL reallocate(grid_atom%rad, 1, new_nr)
     436          82 :       CALL reallocate(grid_atom%rad2, 1, new_nr)
     437          82 :       CALL reallocate(grid_atom%wr, 1, new_nr)
     438          82 :       CALL reallocate(grid_atom%weight, 1, na, 1, new_nr)
     439          82 :       CALL reallocate(grid_atom%rad2l, 1, new_nr, 0, llmax_p1)
     440          82 :       CALL reallocate(grid_atom%oorad2l, 1, new_nr, 0, llmax_p1)
     441             : 
     442          82 :    END SUBROUTINE truncate_radial_grid
     443             : 
     444             : ! **************************************************************************************************
     445             : !> \brief Computes the contraction coefficients to go from spherical orbitals to sgf for a given
     446             : !>        atomic kind and a given basis type.
     447             : !> \param ikind the kind for which we compute the coefficients
     448             : !> \param basis_type the type of basis for which we compute
     449             : !> \param sphi_so where the new contraction coefficients are stored (not yet allocated)
     450             : !> \param qs_env ...
     451             : ! **************************************************************************************************
     452         134 :    SUBROUTINE compute_sphi_so(ikind, basis_type, sphi_so, qs_env)
     453             : 
     454             :       INTEGER, INTENT(IN)                                :: ikind
     455             :       CHARACTER(len=*), INTENT(IN)                       :: basis_type
     456             :       REAL(dp), DIMENSION(:, :), POINTER                 :: sphi_so
     457             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     458             : 
     459             :       INTEGER                                            :: ico, ipgf, iset, iso, l, lx, ly, lz, &
     460             :                                                             maxso, nset, sgfi, start_c, start_s
     461         134 :       INTEGER, DIMENSION(:), POINTER                     :: lmax, lmin, npgf, nsgf_set
     462         134 :       INTEGER, DIMENSION(:, :), POINTER                  :: first_sgf
     463             :       REAL(dp)                                           :: factor
     464         134 :       REAL(dp), DIMENSION(:, :), POINTER                 :: sphi
     465             :       TYPE(gto_basis_set_type), POINTER                  :: basis
     466         134 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     467             : 
     468         134 :       NULLIFY (basis, lmax, lmin, npgf, nsgf_set, qs_kind_set, first_sgf, sphi)
     469             : 
     470         134 :       CALL get_qs_env(qs_env, qs_kind_set=qs_kind_set)
     471         134 :       CALL get_qs_kind(qs_kind_set(ikind), basis_set=basis, basis_type=basis_type)
     472             :       CALL get_gto_basis_set(basis, lmax=lmax, nset=nset, npgf=npgf, maxso=maxso, lmin=lmin, &
     473         134 :                              nsgf_set=nsgf_set, sphi=sphi, first_sgf=first_sgf)
     474             : 
     475        1026 :       ALLOCATE (sphi_so(maxso, SUM(nsgf_set)))
     476      490452 :       sphi_so = 0.0_dp
     477             : 
     478         624 :       DO iset = 1, nset
     479         490 :          sgfi = first_sgf(1, iset)
     480        2264 :          DO ipgf = 1, npgf(iset)
     481        1640 :             start_s = (ipgf - 1)*nsoset(lmax(iset))
     482        1640 :             start_c = (ipgf - 1)*ncoset(lmax(iset))
     483        5012 :             DO l = lmin(iset), lmax(iset)
     484       12216 :                DO iso = 1, nso(l)
     485       47206 :                   DO ico = 1, nco(l)
     486       36630 :                      lx = indco(1, ico + ncoset(l - 1))
     487       36630 :                      ly = indco(2, ico + ncoset(l - 1))
     488       36630 :                      lz = indco(3, ico + ncoset(l - 1))
     489             : !MK                     factor = orbtramat(l)%s2c(iso, ico) &
     490             : !MK                              *SQRT(4.0_dp*pi/dfac(2*l + 1)*dfac(2*lx - 1)*dfac(2*ly - 1)*dfac(2*lz - 1))
     491       36630 :                      factor = orbtramat(l)%slm_inv(iso, ico)
     492             :                      sphi_so(start_s + nsoset(l - 1) + iso, sgfi:sgfi + nsgf_set(iset) - 1) = &
     493             :                         sphi_so(start_s + nsoset(l - 1) + iso, sgfi:sgfi + nsgf_set(iset) - 1) + &
     494     4183350 :                         factor*sphi(start_c + ncoset(l - 1) + ico, sgfi:sgfi + nsgf_set(iset) - 1)
     495             :                   END DO ! ico
     496             :                END DO ! iso
     497             :             END DO ! l
     498             :          END DO ! ipgf
     499             :       END DO ! iset
     500             : 
     501         268 :    END SUBROUTINE compute_sphi_so
     502             : 
     503             : ! **************************************************************************************************
     504             : !> \brief Find the neighbors of a given set of atoms based on the non-zero blocks of a provided
     505             : !>        overlap matrix. Optionally returns an array containing the indices of all involved atoms
     506             : !>        (the given subset plus all their neighbors, without repetition) AND/OR an array of arrays
     507             : !>        providing the indices of the neighbors of each input atom.
     508             : !> \param base_atoms the set of atoms for which we search neighbors
     509             : !> \param mat_s the overlap matrix used to find neighbors
     510             : !> \param radius the cutoff radius after which atoms are not considered neighbors
     511             : !> \param qs_env ...
     512             : !> \param all_neighbors the array uniquely contatining all indices of all atoms involved
     513             : !> \param neighbor_set array of arrays containing the neighbors of all given atoms
     514             : ! **************************************************************************************************
     515          38 :    SUBROUTINE find_neighbors(base_atoms, mat_s, radius, qs_env, all_neighbors, neighbor_set)
     516             : 
     517             :       INTEGER, DIMENSION(:), INTENT(INOUT)               :: base_atoms
     518             :       TYPE(dbcsr_type), INTENT(IN)                       :: mat_s
     519             :       REAL(dp)                                           :: radius
     520             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     521             :       INTEGER, DIMENSION(:), OPTIONAL, POINTER           :: all_neighbors
     522             :       TYPE(cp_1d_i_p_type), DIMENSION(:), OPTIONAL, &
     523             :          POINTER                                         :: neighbor_set
     524             : 
     525             :       INTEGER                                            :: i, iat, ibase, iblk, jblk, mepos, natom, &
     526             :                                                             nb, nbase
     527          38 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: blk_to_base, inb, who_is_there
     528          38 :       INTEGER, ALLOCATABLE, DIMENSION(:, :)              :: n_neighbors
     529          38 :       LOGICAL, ALLOCATABLE, DIMENSION(:)                 :: is_base_atom
     530             :       REAL(dp)                                           :: dist2, rad2, ri(3), rij(3), rj(3)
     531             :       TYPE(cell_type), POINTER                           :: cell
     532          38 :       TYPE(cp_1d_i_p_type), DIMENSION(:), POINTER        :: my_neighbor_set
     533             :       TYPE(dbcsr_iterator_type)                          :: iter
     534             :       TYPE(mp_para_env_type), POINTER                    :: para_env
     535          38 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     536             : 
     537          38 :       NULLIFY (particle_set, para_env, my_neighbor_set, cell)
     538             : 
     539             :       ! Initialization
     540          38 :       CALL get_qs_env(qs_env, para_env=para_env, natom=natom, particle_set=particle_set, cell=cell)
     541          38 :       mepos = para_env%mepos
     542          38 :       nbase = SIZE(base_atoms)
     543             :       !work with the neighbor_set structure, see at the end if we keep it
     544         160 :       ALLOCATE (my_neighbor_set(nbase))
     545          38 :       rad2 = radius**2
     546             : 
     547         152 :       ALLOCATE (blk_to_base(natom), is_base_atom(natom))
     548         816 :       blk_to_base = 0; is_base_atom = .FALSE.
     549          84 :       DO ibase = 1, nbase
     550          46 :          blk_to_base(base_atoms(ibase)) = ibase
     551          84 :          is_base_atom(base_atoms(ibase)) = .TRUE.
     552             :       END DO
     553             : 
     554             :       ! First loop over S => count the number of neighbors
     555         152 :       ALLOCATE (n_neighbors(nbase, 0:para_env%num_pe - 1))
     556         206 :       n_neighbors = 0
     557             : 
     558          38 :       CALL dbcsr_iterator_readonly_start(iter, mat_s)
     559        3814 :       DO WHILE (dbcsr_iterator_blocks_left(iter))
     560             : 
     561        3776 :          CALL dbcsr_iterator_next_block(iter, row=iblk, column=jblk)
     562             : 
     563             :          !avoid self-neighbors
     564        3776 :          IF (iblk == jblk) CYCLE
     565             : 
     566             :          !test distance
     567        3591 :          ri = pbc(particle_set(iblk)%r, cell)
     568        3591 :          rj = pbc(particle_set(jblk)%r, cell)
     569        3591 :          rij = pbc(ri, rj, cell)
     570       14364 :          dist2 = SUM(rij**2)
     571        3591 :          IF (dist2 > rad2) CYCLE
     572             : 
     573          11 :          IF (is_base_atom(iblk)) THEN
     574           6 :             ibase = blk_to_base(iblk)
     575           6 :             n_neighbors(ibase, mepos) = n_neighbors(ibase, mepos) + 1
     576             :          END IF
     577          49 :          IF (is_base_atom(jblk)) THEN
     578           3 :             ibase = blk_to_base(jblk)
     579           3 :             n_neighbors(ibase, mepos) = n_neighbors(ibase, mepos) + 1
     580             :          END IF
     581             : 
     582             :       END DO !iter
     583          38 :       CALL dbcsr_iterator_stop(iter)
     584          38 :       CALL para_env%sum(n_neighbors)
     585             : 
     586             :       ! Allocate the neighbor_set arrays at the correct length
     587          84 :       DO ibase = 1, nbase
     588         190 :          ALLOCATE (my_neighbor_set(ibase)%array(SUM(n_neighbors(ibase, :))))
     589         102 :          my_neighbor_set(ibase)%array = 0
     590             :       END DO
     591             : 
     592             :       ! Loop a second time over S, this time fill the neighbors details
     593          38 :       CALL dbcsr_iterator_readonly_start(iter, mat_s)
     594         114 :       ALLOCATE (inb(nbase))
     595          84 :       inb = 1
     596        3814 :       DO WHILE (dbcsr_iterator_blocks_left(iter))
     597             : 
     598        3776 :          CALL dbcsr_iterator_next_block(iter, row=iblk, column=jblk)
     599        3776 :          IF (iblk == jblk) CYCLE
     600             : 
     601             :          !test distance
     602        3591 :          ri = pbc(particle_set(iblk)%r, cell)
     603        3591 :          rj = pbc(particle_set(jblk)%r, cell)
     604        3591 :          rij = pbc(ri, rj, cell)
     605       14364 :          dist2 = SUM(rij**2)
     606        3591 :          IF (dist2 > rad2) CYCLE
     607             : 
     608          11 :          IF (is_base_atom(iblk)) THEN
     609           6 :             ibase = blk_to_base(iblk)
     610          10 :             my_neighbor_set(ibase)%array(SUM(n_neighbors(ibase, 0:mepos - 1)) + inb(ibase)) = jblk
     611           6 :             inb(ibase) = inb(ibase) + 1
     612             :          END IF
     613          49 :          IF (is_base_atom(jblk)) THEN
     614           3 :             ibase = blk_to_base(jblk)
     615           4 :             my_neighbor_set(ibase)%array(SUM(n_neighbors(ibase, 0:mepos - 1)) + inb(ibase)) = iblk
     616           3 :             inb(ibase) = inb(ibase) + 1
     617             :          END IF
     618             : 
     619             :       END DO !iter
     620          38 :       CALL dbcsr_iterator_stop(iter)
     621             : 
     622             :       ! Make sure the info is shared among the procs
     623          84 :       DO ibase = 1, nbase
     624         120 :          CALL para_env%sum(my_neighbor_set(ibase)%array)
     625             :       END DO
     626             : 
     627             :       ! Gather all indices if asked for it
     628          38 :       IF (PRESENT(all_neighbors)) THEN
     629         114 :          ALLOCATE (who_is_there(natom))
     630         408 :          who_is_there = 0
     631             : 
     632          84 :          DO ibase = 1, nbase
     633          46 :             who_is_there(base_atoms(ibase)) = 1
     634         102 :             DO nb = 1, SIZE(my_neighbor_set(ibase)%array)
     635          64 :                who_is_there(my_neighbor_set(ibase)%array(nb)) = 1
     636             :             END DO
     637             :          END DO
     638             : 
     639          76 :          ALLOCATE (all_neighbors(natom))
     640          38 :          i = 0
     641         408 :          DO iat = 1, natom
     642         408 :             IF (who_is_there(iat) == 1) THEN
     643          56 :                i = i + 1
     644          56 :                all_neighbors(i) = iat
     645             :             END IF
     646             :          END DO
     647          38 :          CALL reallocate(all_neighbors, 1, i)
     648             :       END IF
     649             : 
     650             :       ! If not asked for the neighbor set, deallocate it
     651          38 :       IF (PRESENT(neighbor_set)) THEN
     652          38 :          neighbor_set => my_neighbor_set
     653             :       ELSE
     654           0 :          DO ibase = 1, nbase
     655           0 :             DEALLOCATE (my_neighbor_set(ibase)%array)
     656             :          END DO
     657           0 :          DEALLOCATE (my_neighbor_set)
     658             :       END IF
     659             : 
     660         152 :    END SUBROUTINE find_neighbors
     661             : 
     662             : ! **************************************************************************************************
     663             : !> \brief Returns the RI inverse overlap for a subset of the RI_XAS matrix spaning a given
     664             : !>        excited atom and its neighbors.
     665             : !> \param ri_sinv the inverse overlap as a dbcsr matrix
     666             : !> \param whole_s the whole RI overlap matrix
     667             : !> \param neighbors the indeces of the excited atom and their neighbors
     668             : !> \param idx_to_nb array telling where any atom can be found in neighbors (if there at all)
     669             : !> \param basis_set_ri the RI basis set list for all kinds
     670             : !> \param qs_env ...
     671             : !> \note It is assumed that the neighbors are sorted, the output matrix is assumed to be small and
     672             : !>       is replicated on all processors
     673             : ! **************************************************************************************************
     674          46 :    SUBROUTINE get_exat_ri_sinv(ri_sinv, whole_s, neighbors, idx_to_nb, basis_set_ri, qs_env)
     675             : 
     676             :       TYPE(dbcsr_type)                                   :: ri_sinv, whole_s
     677             :       INTEGER, DIMENSION(:), INTENT(IN)                  :: neighbors, idx_to_nb
     678             :       TYPE(gto_basis_set_p_type), DIMENSION(:), POINTER  :: basis_set_ri
     679             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     680             : 
     681             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'get_exat_ri_sinv'
     682             : 
     683             :       INTEGER                                            :: blk, dest, group_handle, handle, iat, &
     684             :                                                             ikind, inb, ir, is, jat, jnb, natom, &
     685             :                                                             nnb, npcols, nprows, source, tag
     686          46 :       INTEGER, DIMENSION(:), POINTER                     :: col_dist, nsgf, row_dist
     687          46 :       INTEGER, DIMENSION(:, :), POINTER                  :: pgrid
     688             :       LOGICAL                                            :: found_risinv, found_whole
     689          46 :       LOGICAL, ALLOCATABLE, DIMENSION(:)                 :: is_neighbor
     690             :       REAL(dp)                                           :: ri(3), rij(3), rj(3)
     691          46 :       REAL(dp), ALLOCATABLE, DIMENSION(:)                :: radius
     692          46 :       REAL(dp), DIMENSION(:, :), POINTER                 :: block_risinv, block_whole
     693             :       TYPE(cell_type), POINTER                           :: cell
     694          46 :       TYPE(cp_2d_r_p_type), ALLOCATABLE, DIMENSION(:)    :: recv_buff, send_buff
     695             :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env
     696             :       TYPE(dbcsr_distribution_type)                      :: sinv_dist
     697             :       TYPE(dbcsr_distribution_type), POINTER             :: dbcsr_dist
     698             :       TYPE(dbcsr_iterator_type)                          :: iter
     699             :       TYPE(mp_comm_type)                                 :: group
     700             :       TYPE(mp_para_env_type), POINTER                    :: para_env
     701          46 :       TYPE(mp_request_type), ALLOCATABLE, DIMENSION(:)   :: recv_req, send_req
     702          46 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     703             : 
     704          46 :       NULLIFY (pgrid, dbcsr_dist, row_dist, col_dist, nsgf, particle_set, block_whole, block_risinv)
     705          46 :       NULLIFY (cell, para_env, blacs_env)
     706             : 
     707          46 :       CALL timeset(routineN, handle)
     708             : 
     709             :       CALL get_qs_env(qs_env, dbcsr_dist=dbcsr_dist, particle_set=particle_set, natom=natom, &
     710          46 :                       para_env=para_env, blacs_env=blacs_env, cell=cell)
     711          46 :       nnb = SIZE(neighbors)
     712         322 :       ALLOCATE (nsgf(nnb), is_neighbor(natom), radius(nnb))
     713         626 :       is_neighbor = .FALSE.
     714         110 :       DO inb = 1, nnb
     715          64 :          iat = neighbors(inb)
     716          64 :          ikind = particle_set(iat)%atomic_kind%kind_number
     717          64 :          CALL get_gto_basis_set(basis_set_ri(ikind)%gto_basis_set, nsgf=nsgf(inb), kind_radius=radius(inb))
     718         110 :          is_neighbor(iat) = .TRUE.
     719             :       END DO
     720             : 
     721             :       !Create the ri_sinv matrix based on some arbitrary dbcsr_dist
     722          46 :       CALL dbcsr_distribution_get(dbcsr_dist, group=group_handle, pgrid=pgrid, nprows=nprows, npcols=npcols)
     723          46 :       CALL group%set_handle(group_handle)
     724             : 
     725         138 :       ALLOCATE (row_dist(nnb), col_dist(nnb))
     726         110 :       DO inb = 1, nnb
     727          64 :          row_dist(inb) = MODULO(nprows - inb, nprows)
     728         110 :          col_dist(inb) = MODULO(npcols - inb, npcols)
     729             :       END DO
     730             : 
     731             :       CALL dbcsr_distribution_new(sinv_dist, group=group_handle, pgrid=pgrid, row_dist=row_dist, &
     732          46 :                                   col_dist=col_dist)
     733             : 
     734             :       CALL dbcsr_create(matrix=ri_sinv, name="RI_SINV", matrix_type=dbcsr_type_symmetric, &
     735          46 :                         dist=sinv_dist, row_blk_size=nsgf, col_blk_size=nsgf)
     736             :       !reserving the blocks in the correct pattern
     737         110 :       DO inb = 1, nnb
     738          64 :          ri = pbc(particle_set(neighbors(inb))%r, cell)
     739         210 :          DO jnb = inb, nnb
     740             : 
     741             :             !do the atom overlap ?
     742         100 :             rj = pbc(particle_set(neighbors(jnb))%r, cell)
     743         100 :             rij = pbc(ri, rj, cell)
     744         400 :             IF (SUM(rij**2) > (radius(inb) + radius(jnb))**2) CYCLE
     745             : 
     746         100 :             CALL dbcsr_get_stored_coordinates(ri_sinv, inb, jnb, blk)
     747         164 :             IF (para_env%mepos == blk) THEN
     748         200 :                ALLOCATE (block_risinv(nsgf(inb), nsgf(jnb)))
     749      183897 :                block_risinv = 0.0_dp
     750          50 :                CALL dbcsr_put_block(ri_sinv, inb, jnb, block_risinv)
     751          50 :                DEALLOCATE (block_risinv)
     752             :             END IF
     753             :          END DO
     754             :       END DO
     755          46 :       CALL dbcsr_finalize(ri_sinv)
     756             : 
     757          46 :       CALL dbcsr_distribution_release(sinv_dist)
     758          46 :       DEALLOCATE (row_dist, col_dist)
     759             : 
     760             :       !prepare the send and recv buffers we will need for change of dist between the two matrices
     761             :       !worst case scenario: all neighbors are on same procs => need to send nnb**2 messages
     762         502 :       ALLOCATE (send_buff(nnb**2), recv_buff(nnb**2))
     763         548 :       ALLOCATE (send_req(nnb**2), recv_req(nnb**2))
     764          46 :       is = 0; ir = 0
     765             : 
     766             :       !Loop over the whole RI overlap matrix and pick the blocks we need
     767          46 :       CALL dbcsr_iterator_start(iter, whole_s)
     768        7403 :       DO WHILE (dbcsr_iterator_blocks_left(iter))
     769             : 
     770        7357 :          CALL dbcsr_iterator_next_block(iter, row=iat, column=jat)
     771        7357 :          CALL dbcsr_get_block_p(whole_s, iat, jat, block_whole, found_whole)
     772             : 
     773             :          !only interested in neighbors
     774        7357 :          IF (.NOT. found_whole) CYCLE
     775        7357 :          IF (.NOT. is_neighbor(iat)) CYCLE
     776         204 :          IF (.NOT. is_neighbor(jat)) CYCLE
     777             : 
     778          50 :          inb = idx_to_nb(iat)
     779          50 :          jnb = idx_to_nb(jat)
     780             : 
     781             :          !If blocks are on the same proc for both matrices, simply copy
     782          50 :          CALL dbcsr_get_block_p(ri_sinv, inb, jnb, block_risinv, found_risinv)
     783          96 :          IF (found_risinv) THEN
     784           4 :             CALL dcopy(nsgf(inb)*nsgf(jnb), block_whole, 1, block_risinv, 1)
     785             :          ELSE
     786             : 
     787             :             !send the block with unique tag to the proc where inb,jnb is in ri_sinv
     788          46 :             CALL dbcsr_get_stored_coordinates(ri_sinv, inb, jnb, dest)
     789          46 :             is = is + 1
     790          46 :             send_buff(is)%array => block_whole
     791          46 :             tag = natom*inb + jnb
     792          46 :             CALL group%isend(msgin=send_buff(is)%array, dest=dest, request=send_req(is), tag=tag)
     793             : 
     794             :          END IF
     795             : 
     796             :       END DO !dbcsr iter
     797          46 :       CALL dbcsr_iterator_stop(iter)
     798             : 
     799             :       !Loop over ri_sinv and receive all those blocks
     800          46 :       CALL dbcsr_iterator_start(iter, ri_sinv)
     801          96 :       DO WHILE (dbcsr_iterator_blocks_left(iter))
     802             : 
     803          50 :          CALL dbcsr_iterator_next_block(iter, row=inb, column=jnb)
     804          50 :          CALL dbcsr_get_block_p(ri_sinv, inb, jnb, block_risinv, found_risinv)
     805             : 
     806          50 :          IF (.NOT. found_risinv) CYCLE
     807             : 
     808          50 :          iat = neighbors(inb)
     809          50 :          jat = neighbors(jnb)
     810             : 
     811             :          !If blocks are on the same proc on both matrices do nothing
     812          50 :          CALL dbcsr_get_stored_coordinates(whole_s, iat, jat, source)
     813          50 :          IF (para_env%mepos == source) CYCLE
     814             : 
     815          46 :          tag = natom*inb + jnb
     816          46 :          ir = ir + 1
     817          46 :          recv_buff(ir)%array => block_risinv
     818             :          CALL group%irecv(msgout=recv_buff(ir)%array, source=source, request=recv_req(ir), &
     819          96 :                           tag=tag)
     820             : 
     821             :       END DO
     822          46 :       CALL dbcsr_iterator_stop(iter)
     823             : 
     824             :       !make sure that all comm is over before proceeding
     825          46 :       CALL mp_waitall(send_req(1:is))
     826          46 :       CALL mp_waitall(recv_req(1:ir))
     827             : 
     828             :       !Invert. 2 cases: with or without neighbors. If no neighbors, easier to invert on one proc and
     829             :       !avoid the whole fm to dbcsr to fm that is quite expensive
     830          46 :       IF (nnb == 1) THEN
     831             : 
     832          40 :          CALL dbcsr_get_block_p(ri_sinv, 1, 1, block_risinv, found_risinv)
     833          40 :          IF (found_risinv) THEN
     834          20 :             CALL invmat_symm(block_risinv)
     835             :          END IF
     836             : 
     837             :       ELSE
     838           6 :          CALL cp_dbcsr_cholesky_decompose(ri_sinv, para_env=para_env, blacs_env=blacs_env)
     839           6 :          CALL cp_dbcsr_cholesky_invert(ri_sinv, para_env=para_env, blacs_env=blacs_env, uplo_to_full=.TRUE.)
     840           6 :          CALL dbcsr_filter(ri_sinv, 1.E-10_dp) !make sure ri_sinv is sparse coming out of fm routines
     841             :       END IF
     842          46 :       CALL dbcsr_replicate_all(ri_sinv)
     843             : 
     844             :       !clean-up
     845          46 :       DEALLOCATE (nsgf)
     846             : 
     847          46 :       CALL timestop(handle)
     848             : 
     849         276 :    END SUBROUTINE get_exat_ri_sinv
     850             : 
     851             : ! **************************************************************************************************
     852             : !> \brief Compute the coefficients to project the density on a partial RI_XAS basis
     853             : !> \param xas_atom_env ...
     854             : !> \param qs_env ...
     855             : !> \note The density is n = sum_ab P_ab*phi_a*phi_b, the RI basis covers the products of orbital sgfs
     856             : !>       => n = sum_ab sum_cd P_ab (phi_a phi_b xi_c) S_cd^-1 xi_d
     857             : !>            = sum_d coeff_d xi_d , where xi are the RI basis func.
     858             : !>       In this case, with the partial RI projection, the RI basis is restricted to an excited atom
     859             : !>       and its neighbors at a time. Leads to smaller overlap matrix to invert and less 3-center
     860             : !>       overlap to compute. The procedure is repeated for each excited atom
     861             : ! **************************************************************************************************
     862          38 :    SUBROUTINE calculate_density_coeffs(xas_atom_env, qs_env)
     863             : 
     864             :       TYPE(xas_atom_env_type), POINTER                   :: xas_atom_env
     865             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     866             : 
     867             :       CHARACTER(len=*), PARAMETER :: routineN = 'calculate_density_coeffs'
     868             : 
     869             :       INTEGER                                            :: exat, handle, i, iat, iatom, iex, inb, &
     870             :                                                             ind(3), ispin, jatom, jnb, katom, &
     871             :                                                             natom, nex, nkind, nnb, nspins, &
     872             :                                                             output_unit, ri_at
     873          38 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: blk_size_orb, blk_size_ri, idx_to_nb, &
     874          38 :                                                             neighbors
     875          38 :       INTEGER, DIMENSION(:), POINTER                     :: all_ri_atoms
     876             :       LOGICAL                                            :: pmat_found, pmat_foundt, sinv_found, &
     877             :                                                             sinv_foundt, tensor_found, unique
     878             :       REAL(dp)                                           :: factor, prefac
     879          38 :       REAL(dp), ALLOCATABLE, DIMENSION(:)                :: work2
     880          38 :       REAL(dp), ALLOCATABLE, DIMENSION(:, :)             :: work1
     881          38 :       REAL(dp), ALLOCATABLE, DIMENSION(:, :, :)          :: t_block
     882          76 :       REAL(dp), DIMENSION(:, :), POINTER                 :: pmat_block, pmat_blockt, sinv_block, &
     883          38 :                                                             sinv_blockt
     884             :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env
     885             :       TYPE(dbcsr_distribution_type), POINTER             :: dbcsr_dist
     886          76 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: overlap, rho_ao
     887             :       TYPE(dbcsr_type)                                   :: ri_sinv
     888             :       TYPE(dbcsr_type), POINTER                          :: ri_mats
     889             :       TYPE(dbt_iterator_type)                            :: iter
     890         342 :       TYPE(dbt_type)                                     :: pqX
     891          38 :       TYPE(gto_basis_set_p_type), DIMENSION(:), POINTER  :: basis_set_orb, basis_set_ri
     892             :       TYPE(libint_potential_type)                        :: pot
     893             :       TYPE(mp_para_env_type), POINTER                    :: para_env
     894             :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
     895          76 :          POINTER                                         :: ab_list, ac_list, sab_ri
     896          38 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     897          38 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     898             :       TYPE(qs_rho_type), POINTER                         :: rho
     899             : 
     900          38 :       NULLIFY (qs_kind_set, basis_set_ri, basis_set_orb, ac_list, rho, rho_ao, sab_ri, ri_mats)
     901          38 :       NULLIFY (particle_set, para_env, all_ri_atoms, overlap, pmat_blockt)
     902          38 :       NULLIFY (blacs_env, pmat_block, ab_list, dbcsr_dist, sinv_block, sinv_blockt)
     903             : 
     904             :       !Idea: We don't do a full RI here as it would be too expensive in many ways (inversion of a
     905             :       !      large matrix, many 3-center overlaps, density coefficients for all atoms, etc...)
     906             :       !      Instead, we go excited atom by excited atom and only do a RI expansion on its basis
     907             :       !      and that of its closest neighbors (defined through RI_RADIUS), such that we only have
     908             :       !      very small matrices to invert and only a few (abc) overlp integrals with c on the
     909             :       !      excited atom its neighbors. This is physically sound since we only need the density
     910             :       !      well defined on the excited atom grid as we do (aI|P)*(P|Q)^-1*(Q|fxc|R)*(R|S)^-1*(S|Jb)
     911             : 
     912          38 :       CALL timeset(routineN, handle)
     913             : 
     914             :       CALL get_qs_env(qs_env, nkind=nkind, qs_kind_set=qs_kind_set, rho=rho, &
     915             :                       natom=natom, particle_set=particle_set, dbcsr_dist=dbcsr_dist, &
     916          38 :                       para_env=para_env, blacs_env=blacs_env)
     917          38 :       nspins = xas_atom_env%nspins
     918          38 :       nex = SIZE(xas_atom_env%excited_atoms)
     919          38 :       CALL qs_rho_get(rho, rho_ao=rho_ao)
     920             : 
     921             : !  Create the needed neighbor list and basis set lists.
     922         174 :       ALLOCATE (basis_set_ri(nkind))
     923         136 :       ALLOCATE (basis_set_orb(nkind))
     924          38 :       CALL basis_set_list_setup(basis_set_ri, "RI_XAS", qs_kind_set)
     925          38 :       CALL basis_set_list_setup(basis_set_orb, "ORB", qs_kind_set)
     926             : 
     927             : !  Compute the RI overlap matrix on the whole system
     928          38 :       CALL build_xas_tdp_ovlp_nl(sab_ri, basis_set_ri, basis_set_ri, qs_env)
     929          38 :       CALL build_overlap_matrix_simple(qs_env%ks_env, overlap, basis_set_ri, basis_set_ri, sab_ri)
     930          38 :       ri_mats => overlap(1)%matrix
     931          38 :       CALL release_neighbor_list_sets(sab_ri)
     932             : 
     933             : !  Get the neighbors of the excited atoms (= all the atoms where density coeffs are needed)
     934             :       CALL find_neighbors(xas_atom_env%excited_atoms, ri_mats, xas_atom_env%ri_radius, &
     935          38 :                           qs_env, all_neighbors=all_ri_atoms, neighbor_set=xas_atom_env%exat_neighbors)
     936             : 
     937             :       !keep in mind that double occupation is included in rho_ao in case of closed-shell
     938          38 :       factor = 0.5_dp; IF (nspins == 2) factor = 1.0_dp
     939             : 
     940             : !  Allocate space for the projected density coefficients. On all ri_atoms.
     941             : !  Note: the sub-region where we project the density changes from excited atom to excited atom
     942             : !        => need different sets of RI coeffs
     943         114 :       ALLOCATE (blk_size_ri(natom))
     944          38 :       CALL get_particle_set(particle_set, qs_kind_set, nsgf=blk_size_ri, basis=basis_set_ri)
     945         872 :       ALLOCATE (xas_atom_env%ri_dcoeff(natom, nspins, nex))
     946          84 :       DO iex = 1, nex
     947         132 :          DO ispin = 1, nspins
     948         682 :             DO iat = 1, natom
     949         588 :                NULLIFY (xas_atom_env%ri_dcoeff(iat, ispin, iex)%array)
     950             :                IF ((.NOT. ANY(xas_atom_env%exat_neighbors(iex)%array == iat)) &
     951         636 :                    .AND. (.NOT. xas_atom_env%excited_atoms(iex) == iat)) CYCLE
     952         216 :                ALLOCATE (xas_atom_env%ri_dcoeff(iat, ispin, iex)%array(blk_size_ri(iat)))
     953        4450 :                xas_atom_env%ri_dcoeff(iat, ispin, iex)%array = 0.0_dp
     954             :             END DO
     955             :          END DO
     956             :       END DO
     957             : 
     958          38 :       output_unit = cp_logger_get_default_io_unit()
     959          38 :       IF (output_unit > 0) THEN
     960             :          WRITE (output_unit, FMT="(/,T7,A,/,T7,A)") &
     961          19 :             "Excited atom, natoms in RI_REGION:", &
     962          38 :             "---------------------------------"
     963             :       END IF
     964             : 
     965             :       !We go atom by atom, first computing the integrals themselves that we put into a tensor, then we do
     966             :       !the contraction with the density. We do that in the original dist, which is optimized for overlap
     967             : 
     968         114 :       ALLOCATE (blk_size_orb(natom))
     969          38 :       CALL get_particle_set(particle_set, qs_kind_set, nsgf=blk_size_orb, basis=basis_set_orb)
     970             : 
     971          84 :       DO iex = 1, nex
     972             : 
     973             :          !get neighbors of current atom
     974          46 :          exat = xas_atom_env%excited_atoms(iex)
     975          46 :          nnb = 1 + SIZE(xas_atom_env%exat_neighbors(iex)%array)
     976         138 :          ALLOCATE (neighbors(nnb))
     977          46 :          neighbors(1) = exat
     978          64 :          neighbors(2:nnb) = xas_atom_env%exat_neighbors(iex)%array(:)
     979          46 :          CALL sort_unique(neighbors, unique)
     980             : 
     981             :          !link the atoms to their position in neighbors
     982         138 :          ALLOCATE (idx_to_nb(natom))
     983         626 :          idx_to_nb = 0
     984         110 :          DO inb = 1, nnb
     985         110 :             idx_to_nb(neighbors(inb)) = inb
     986             :          END DO
     987             : 
     988          46 :          IF (output_unit > 0) THEN
     989             :             WRITE (output_unit, FMT="(T7,I12,I21)") &
     990          23 :                exat, nnb
     991             :          END IF
     992             : 
     993             :          !Get the neighbor lists for the overlap integrals (abc), centers c on the current
     994             :          !excited atom and its neighbors defined by RI_RADIUS
     995          46 :          CALL build_xas_tdp_ovlp_nl(ab_list, basis_set_orb, basis_set_orb, qs_env)
     996             :          CALL build_xas_tdp_3c_nl(ac_list, basis_set_orb, basis_set_ri, do_potential_id, &
     997          46 :                                   qs_env, excited_atoms=neighbors)
     998             : 
     999             :          !Compute the 3-center overlap integrals
    1000          46 :          pot%potential_type = do_potential_id
    1001             : 
    1002             :          CALL create_pqX_tensor(pqX, ab_list, ac_list, dbcsr_dist, blk_size_orb, blk_size_orb, &
    1003          46 :                                 blk_size_ri)
    1004             :          CALL fill_pqX_tensor(pqX, ab_list, ac_list, basis_set_orb, basis_set_orb, basis_set_ri, &
    1005          46 :                               pot, qs_env)
    1006             : 
    1007             :          !Compute the RI inverse overlap matrix on the reduced RI basis that spans the excited
    1008             :          !atom and its neighbors, ri_sinv is replicated over all procs
    1009          46 :          CALL get_exat_ri_sinv(ri_sinv, ri_mats, neighbors, idx_to_nb, basis_set_ri, qs_env)
    1010             : 
    1011             :          !Do the actual contraction: coeff_y = sum_pq sum_x P_pq (phi_p phi_q xi_x) S_xy^-1
    1012             : 
    1013             : !$OMP PARALLEL DEFAULT(NONE) &
    1014             : !$OMP SHARED(pqX,rho_ao,ri_sinv,xas_atom_env) &
    1015             : !$OMP SHARED(blk_size_ri,idx_to_nb,nspins,nnb,neighbors,iex,factor) &
    1016             : !$OMP PRIVATE(iter,ind,t_block,tensor_found,iatom,jatom,katom,inb,prefac,ispin) &
    1017             : !$OMP PRIVATE(pmat_block,pmat_found,pmat_blockt,pmat_foundt,work1,work2,jnb,ri_at) &
    1018          46 : !$OMP PRIVATE(sinv_block,sinv_found,sinv_blockt,sinv_foundt)
    1019             :          CALL dbt_iterator_start(iter, pqX)
    1020             :          DO WHILE (dbt_iterator_blocks_left(iter))
    1021             :             CALL dbt_iterator_next_block(iter, ind)
    1022             :             CALL dbt_get_block(pqX, ind, t_block, tensor_found)
    1023             : 
    1024             :             iatom = ind(1)
    1025             :             jatom = ind(2)
    1026             :             katom = ind(3)
    1027             :             inb = idx_to_nb(katom)
    1028             : 
    1029             :             !non-diagonal elements need to be counted twice
    1030             :             prefac = 2.0_dp
    1031             :             IF (iatom == jatom) prefac = 1.0_dp
    1032             : 
    1033             :             DO ispin = 1, nspins
    1034             : 
    1035             :                !rho_ao is symmetric, block can be in either location
    1036             :                CALL dbcsr_get_block_p(rho_ao(ispin)%matrix, iatom, jatom, pmat_block, pmat_found)
    1037             :                CALL dbcsr_get_block_p(rho_ao(ispin)%matrix, jatom, iatom, pmat_blockt, pmat_foundt)
    1038             :                IF ((.NOT. pmat_found) .AND. (.NOT. pmat_foundt)) CYCLE
    1039             : 
    1040             :                ALLOCATE (work1(blk_size_ri(katom), 1))
    1041             :                work1 = 0.0_dp
    1042             : 
    1043             :                !first contraction with the density matrix
    1044             :                IF (pmat_found) THEN
    1045             :                   DO i = 1, blk_size_ri(katom)
    1046             :                      work1(i, 1) = prefac*SUM(pmat_block(:, :)*t_block(:, :, i))
    1047             :                   END DO
    1048             :                ELSE
    1049             :                   DO i = 1, blk_size_ri(katom)
    1050             :                      work1(i, 1) = prefac*SUM(TRANSPOSE(pmat_blockt(:, :))*t_block(:, :, i))
    1051             :                   END DO
    1052             :                END IF
    1053             : 
    1054             :                !loop over neighbors
    1055             :                DO jnb = 1, nnb
    1056             : 
    1057             :                   ri_at = neighbors(jnb)
    1058             : 
    1059             :                   !ri_sinv is a symmetric matrix => actual block is one of the two
    1060             :                   CALL dbcsr_get_block_p(ri_sinv, inb, jnb, sinv_block, sinv_found)
    1061             :                   CALL dbcsr_get_block_p(ri_sinv, jnb, inb, sinv_blockt, sinv_foundt)
    1062             :                   IF ((.NOT. sinv_found) .AND. (.NOT. sinv_foundt)) CYCLE
    1063             : 
    1064             :                   !second contraction with the inverse RI overlap
    1065             :                   ALLOCATE (work2(SIZE(xas_atom_env%ri_dcoeff(ri_at, ispin, iex)%array)))
    1066             :                   work2 = 0.0_dp
    1067             : 
    1068             :                   IF (sinv_found) THEN
    1069             :                      DO i = 1, blk_size_ri(katom)
    1070             :                         work2(:) = work2(:) + factor*work1(i, 1)*sinv_block(i, :)
    1071             :                      END DO
    1072             :                   ELSE
    1073             :                      DO i = 1, blk_size_ri(katom)
    1074             :                         work2(:) = work2(:) + factor*work1(i, 1)*sinv_blockt(:, i)
    1075             :                      END DO
    1076             :                   END IF
    1077             :                   DO i = 1, SIZE(work2)
    1078             : !$OMP ATOMIC
    1079             :                      xas_atom_env%ri_dcoeff(ri_at, ispin, iex)%array(i) = &
    1080             :                         xas_atom_env%ri_dcoeff(ri_at, ispin, iex)%array(i) + work2(i)
    1081             :                   END DO
    1082             : 
    1083             :                   DEALLOCATE (work2)
    1084             :                END DO !jnb
    1085             : 
    1086             :                DEALLOCATE (work1)
    1087             :             END DO
    1088             : 
    1089             :             DEALLOCATE (t_block)
    1090             :          END DO !iter
    1091             :          CALL dbt_iterator_stop(iter)
    1092             : !$OMP END PARALLEL
    1093             : 
    1094             :          !clean-up
    1095          46 :          CALL dbcsr_release(ri_sinv)
    1096          46 :          CALL dbt_destroy(pqX)
    1097          46 :          CALL release_neighbor_list_sets(ab_list)
    1098          46 :          CALL release_neighbor_list_sets(ac_list)
    1099         130 :          DEALLOCATE (neighbors, idx_to_nb)
    1100             : 
    1101             :       END DO !iex
    1102             : 
    1103             :       !making sure all procs have the same info
    1104          84 :       DO iex = 1, nex
    1105         132 :          DO ispin = 1, nspins
    1106         682 :             DO iat = 1, natom
    1107             :                IF ((.NOT. ANY(xas_atom_env%exat_neighbors(iex)%array == iat)) &
    1108         636 :                    .AND. (.NOT. xas_atom_env%excited_atoms(iex) == iat)) CYCLE
    1109        9296 :                CALL para_env%sum(xas_atom_env%ri_dcoeff(iat, ispin, iex)%array)
    1110             :             END DO !iat
    1111             :          END DO !ispin
    1112             :       END DO !iex
    1113             : 
    1114             : !  clean-up
    1115          38 :       CALL dbcsr_deallocate_matrix_set(overlap)
    1116          38 :       DEALLOCATE (basis_set_ri, basis_set_orb, all_ri_atoms)
    1117             : 
    1118          38 :       CALL timestop(handle)
    1119             : 
    1120         114 :    END SUBROUTINE calculate_density_coeffs
    1121             : 
    1122             : ! **************************************************************************************************
    1123             : !> \brief Evaluates the density on a given atomic grid
    1124             : !> \param rho_set where the densities are stored
    1125             : !> \param ri_dcoeff the arrays containing the RI density coefficients of this atom, for each spin
    1126             : !> \param atom_kind the kind of the atom in question
    1127             : !> \param do_gga whether the gradient of the density should also be put on the grid
    1128             : !> \param batch_info how the so are distributed
    1129             : !> \param xas_atom_env ...
    1130             : !> \param qs_env ...
    1131             : !> \note The density is expressed as n = sum_d coeff_d*xi_d. Knowing the coordinate of each grid
    1132             : !>       grid point, one can simply evaluate xi_d(r)
    1133             : ! **************************************************************************************************
    1134          38 :    SUBROUTINE put_density_on_atomic_grid(rho_set, ri_dcoeff, atom_kind, do_gga, batch_info, &
    1135             :                                          xas_atom_env, qs_env)
    1136             : 
    1137             :       TYPE(xc_rho_set_type), INTENT(INOUT)               :: rho_set
    1138             :       TYPE(cp_1d_r_p_type), DIMENSION(:)                 :: ri_dcoeff
    1139             :       INTEGER, INTENT(IN)                                :: atom_kind
    1140             :       LOGICAL, INTENT(IN)                                :: do_gga
    1141             :       TYPE(batch_info_type)                              :: batch_info
    1142             :       TYPE(xas_atom_env_type), POINTER                   :: xas_atom_env
    1143             :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1144             : 
    1145             :       CHARACTER(len=*), PARAMETER :: routineN = 'put_density_on_atomic_grid'
    1146             : 
    1147             :       INTEGER                                            :: dir, handle, ipgf, iset, iso, iso_proc, &
    1148             :                                                             ispin, maxso, n, na, nr, nset, nsgfi, &
    1149             :                                                             nsoi, nspins, sgfi, starti
    1150          38 :       INTEGER, DIMENSION(:), POINTER                     :: lmax, lmin, npgf, nsgf_set
    1151          38 :       INTEGER, DIMENSION(:, :), POINTER                  :: first_sgf
    1152          38 :       REAL(dp), ALLOCATABLE, DIMENSION(:, :)             :: so
    1153          38 :       REAL(dp), ALLOCATABLE, DIMENSION(:, :, :)          :: dso
    1154          38 :       REAL(dp), DIMENSION(:, :), POINTER                 :: dgr1, dgr2, ga, gr, ri_sphi_so, zet
    1155          38 :       REAL(dp), DIMENSION(:, :, :), POINTER              :: dga1, dga2, rhoa, rhob
    1156          38 :       TYPE(cp_1d_r_p_type), DIMENSION(:), POINTER        :: ri_dcoeff_so
    1157             :       TYPE(grid_atom_type), POINTER                      :: grid_atom
    1158             :       TYPE(gto_basis_set_type), POINTER                  :: ri_basis
    1159          38 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
    1160             : 
    1161          38 :       NULLIFY (grid_atom, ri_basis, qs_kind_set, lmax, npgf, zet, nsgf_set, ri_sphi_so)
    1162          38 :       NULLIFY (lmin, first_sgf, rhoa, rhob, ga, gr, dgr1, dgr2, dga1, dga2, ri_dcoeff_so)
    1163             : 
    1164          38 :       CALL timeset(routineN, handle)
    1165             : 
    1166             : !  Strategy: it makes sense to evaluate the spherical orbital on the grid (because of symmetry)
    1167             : !            From there, one can directly contract into sgf using ri_sphi_so and then take the weight
    1168             : !            The spherical orbital were precomputed and split in a purely radial and a purely
    1169             : !            angular part. The full values on each grid point are obtain through gemm
    1170             : 
    1171             : !  Generalities
    1172          38 :       CALL get_qs_env(qs_env, qs_kind_set=qs_kind_set)
    1173          38 :       CALL get_qs_kind(qs_kind_set(atom_kind), basis_set=ri_basis, basis_type="RI_XAS")
    1174             :       CALL get_gto_basis_set(ri_basis, lmax=lmax, npgf=npgf, zet=zet, nset=nset, nsgf_set=nsgf_set, &
    1175          38 :                              first_sgf=first_sgf, lmin=lmin, maxso=maxso)
    1176             : 
    1177             : !  Get the grid and the info we need from it
    1178          38 :       grid_atom => xas_atom_env%grid_atom_set(atom_kind)%grid_atom
    1179          38 :       na = grid_atom%ng_sphere
    1180          38 :       nr = grid_atom%nr
    1181          38 :       n = na*nr
    1182          38 :       nspins = xas_atom_env%nspins
    1183          38 :       ri_sphi_so => xas_atom_env%ri_sphi_so(atom_kind)%array
    1184             : 
    1185             : !  Point to the rho_set densities
    1186          38 :       rhoa => rho_set%rhoa
    1187          38 :       rhob => rho_set%rhob
    1188     1911146 :       rhoa = 0.0_dp; rhob = 0.0_dp; 
    1189          38 :       IF (do_gga) THEN
    1190          72 :          DO dir = 1, 3
    1191     1575909 :             rho_set%drhoa(dir)%array = 0.0_dp
    1192     1575927 :             rho_set%drhob(dir)%array = 0.0_dp
    1193             :          END DO
    1194             :       END IF
    1195             : 
    1196             : !  Point to the precomputed SO
    1197          38 :       ga => xas_atom_env%ga(atom_kind)%array
    1198          38 :       gr => xas_atom_env%gr(atom_kind)%array
    1199          38 :       IF (do_gga) THEN
    1200          18 :          dga1 => xas_atom_env%dga1(atom_kind)%array
    1201          18 :          dga2 => xas_atom_env%dga2(atom_kind)%array
    1202          18 :          dgr1 => xas_atom_env%dgr1(atom_kind)%array
    1203          18 :          dgr2 => xas_atom_env%dgr2(atom_kind)%array
    1204             :       ELSE
    1205          20 :          dga1 => xas_atom_env%dga1(atom_kind)%array
    1206          20 :          dga2 => xas_atom_env%dga2(atom_kind)%array
    1207          20 :          dgr1 => xas_atom_env%dgr1(atom_kind)%array
    1208          20 :          dgr2 => xas_atom_env%dgr2(atom_kind)%array
    1209             :       END IF
    1210             : 
    1211             : !  Need to express the ri_dcoeffs in terms of so (and not sgf)
    1212         154 :       ALLOCATE (ri_dcoeff_so(nspins))
    1213          78 :       DO ispin = 1, nspins
    1214         120 :          ALLOCATE (ri_dcoeff_so(ispin)%array(nset*maxso))
    1215        7468 :          ri_dcoeff_so(ispin)%array = 0.0_dp
    1216             : 
    1217             :          !for a given so, loop over sgf and sum
    1218         196 :          DO iset = 1, nset
    1219         118 :             sgfi = first_sgf(1, iset)
    1220         118 :             nsoi = npgf(iset)*nsoset(lmax(iset))
    1221         118 :             nsgfi = nsgf_set(iset)
    1222             : 
    1223             :             CALL dgemv('N', nsoi, nsgfi, 1.0_dp, ri_sphi_so(1:nsoi, sgfi:sgfi + nsgfi - 1), nsoi, &
    1224             :                        ri_dcoeff(ispin)%array(sgfi:sgfi + nsgfi - 1), 1, 0.0_dp, &
    1225         158 :                        ri_dcoeff_so(ispin)%array((iset - 1)*maxso + 1:(iset - 1)*maxso + nsoi), 1)
    1226             : 
    1227             :          END DO
    1228             :       END DO
    1229             : 
    1230             :       !allocate space to store the spherical orbitals on the grid
    1231         152 :       ALLOCATE (so(na, nr))
    1232         110 :       IF (do_gga) ALLOCATE (dso(na, nr, 3))
    1233             : 
    1234             : !  Loop over the spherical orbitals on this proc
    1235        4040 :       DO iso_proc = 1, batch_info%nso_proc(atom_kind)
    1236        4002 :          iset = batch_info%so_proc_info(atom_kind)%array(1, iso_proc)
    1237        4002 :          ipgf = batch_info%so_proc_info(atom_kind)%array(2, iso_proc)
    1238        4002 :          iso = batch_info%so_proc_info(atom_kind)%array(3, iso_proc)
    1239        4002 :          IF (iso < 0) CYCLE
    1240             : 
    1241        2150 :          starti = (iset - 1)*maxso + (ipgf - 1)*nsoset(lmax(iset))
    1242             : 
    1243             :          !the spherical orbital on the grid
    1244             :          CALL dgemm('N', 'T', na, nr, 1, 1.0_dp, ga(:, iso_proc:iso_proc), na, &
    1245        2150 :                     gr(:, iso_proc:iso_proc), nr, 0.0_dp, so(:, :), na)
    1246             : 
    1247             :          !the gradient on the grid
    1248        2150 :          IF (do_gga) THEN
    1249             : 
    1250        5020 :             DO dir = 1, 3
    1251             :                CALL dgemm('N', 'T', na, nr, 1, 1.0_dp, dga1(:, iso_proc:iso_proc, dir), na, &
    1252        3765 :                           dgr1(:, iso_proc:iso_proc), nr, 0.0_dp, dso(:, :, dir), na)
    1253             :                CALL dgemm('N', 'T', na, nr, 1, 1.0_dp, dga2(:, iso_proc:iso_proc, dir), na, &
    1254        5020 :                           dgr2(:, iso_proc:iso_proc), nr, 1.0_dp, dso(:, :, dir), na)
    1255             :             END DO
    1256             :          END IF
    1257             : 
    1258             :          !put the so on the grid with the approriate coefficients and sum
    1259        2150 :          CALL daxpy(n, ri_dcoeff_so(1)%array(starti + iso), so, 1, rhoa(:, :, 1), 1)
    1260             : 
    1261        2150 :          IF (nspins == 2) THEN
    1262         126 :             CALL daxpy(n, ri_dcoeff_so(2)%array(starti + iso), so, 1, rhob(:, :, 1), 1)
    1263             :          END IF
    1264             : 
    1265        2188 :          IF (do_gga) THEN
    1266             : 
    1267             :             !put the gradient of the so on the grid with correspond RI coeff
    1268        5020 :             DO dir = 1, 3
    1269             :                CALL daxpy(n, ri_dcoeff_so(1)%array(starti + iso), dso(:, :, dir), &
    1270        3765 :                           1, rho_set%drhoa(dir)%array(:, :, 1), 1)
    1271             : 
    1272        5020 :                IF (nspins == 2) THEN
    1273             :                   CALL daxpy(n, ri_dcoeff_so(2)%array(starti + iso), dso(:, :, dir), &
    1274         378 :                              1, rho_set%drhob(dir)%array(:, :, 1), 1)
    1275             :                END IF
    1276             :             END DO !dir
    1277             :          END IF !do_gga
    1278             : 
    1279             :       END DO
    1280             : 
    1281             : ! Treat spin restricted case (=> copy alpha into beta)
    1282          38 :       IF (nspins == 1) THEN
    1283          36 :          CALL dcopy(n, rhoa(:, :, 1), 1, rhob(:, :, 1), 1)
    1284             : 
    1285          36 :          IF (do_gga) THEN
    1286          64 :             DO dir = 1, 3
    1287          64 :                CALL dcopy(n, rho_set%drhoa(dir)%array(:, :, 1), 1, rho_set%drhob(dir)%array(:, :, 1), 1)
    1288             :             END DO
    1289             :          END IF
    1290             :       END IF
    1291             : 
    1292             : ! Note: sum over procs is done outside
    1293             : 
    1294             : !  clean-up
    1295          78 :       DO ispin = 1, nspins
    1296          78 :          DEALLOCATE (ri_dcoeff_so(ispin)%array)
    1297             :       END DO
    1298          38 :       DEALLOCATE (ri_dcoeff_so)
    1299             : 
    1300          38 :       CALL timestop(handle)
    1301             : 
    1302         114 :    END SUBROUTINE put_density_on_atomic_grid
    1303             : 
    1304             : ! **************************************************************************************************
    1305             : !> \brief Adds the density of a given source atom with source kind (with ri_dcoeff) on the atomic
    1306             : !>        grid belonging to another target atom of target kind. The evaluations of the basis
    1307             : !>        function first requires the evaluation of the x,y,z coordinates on each grid point of
    1308             : !>        target atom wrt to the position of source atom
    1309             : !> \param rho_set where the densities are stored
    1310             : !> \param ri_dcoeff the arrays containing the RI density coefficient of source_iat, for each spin
    1311             : !> \param source_iat the index of the source atom
    1312             : !> \param source_ikind the kind of the source atom
    1313             : !> \param target_iat the index of the target atom
    1314             : !> \param target_ikind the kind of the target atom
    1315             : !> \param sr starting r index for the local grid
    1316             : !> \param er ending r index for the local grid
    1317             : !> \param do_gga whether the gradient of the density is needed
    1318             : !> \param xas_atom_env ...
    1319             : !> \param qs_env ...
    1320             : ! **************************************************************************************************
    1321          12 :    SUBROUTINE put_density_on_other_grid(rho_set, ri_dcoeff, source_iat, source_ikind, target_iat, &
    1322             :                                         target_ikind, sr, er, do_gga, xas_atom_env, qs_env)
    1323             : 
    1324             :       TYPE(xc_rho_set_type), INTENT(INOUT)               :: rho_set
    1325             :       TYPE(cp_1d_r_p_type), DIMENSION(:)                 :: ri_dcoeff
    1326             :       INTEGER, INTENT(IN)                                :: source_iat, source_ikind, target_iat, &
    1327             :                                                             target_ikind, sr, er
    1328             :       LOGICAL, INTENT(IN)                                :: do_gga
    1329             :       TYPE(xas_atom_env_type), POINTER                   :: xas_atom_env
    1330             :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1331             : 
    1332             :       CHARACTER(len=*), PARAMETER :: routineN = 'put_density_on_other_grid'
    1333             : 
    1334             :       INTEGER                                            :: dir, handle, ia, ico, ipgf, ir, iset, &
    1335             :                                                             isgf, lx, ly, lz, n, na, nr, nset, &
    1336             :                                                             nspins, sgfi, start
    1337          12 :       INTEGER, DIMENSION(:), POINTER                     :: lmax, lmin, npgf, nsgf_set
    1338          12 :       INTEGER, DIMENSION(:, :), POINTER                  :: first_sgf
    1339             :       REAL(dp)                                           :: rmom
    1340          12 :       REAL(dp), ALLOCATABLE, DIMENSION(:, :)             :: sgf
    1341          12 :       REAL(dp), ALLOCATABLE, DIMENSION(:, :, :)          :: co, dsgf, pos
    1342          12 :       REAL(dp), ALLOCATABLE, DIMENSION(:, :, :, :)       :: dco
    1343             :       REAL(dp), DIMENSION(3)                             :: rs, rst, rt
    1344          12 :       REAL(dp), DIMENSION(:, :), POINTER                 :: ri_sphi, zet
    1345          12 :       REAL(dp), DIMENSION(:, :, :), POINTER              :: rhoa, rhob
    1346             :       TYPE(cell_type), POINTER                           :: cell
    1347             :       TYPE(grid_atom_type), POINTER                      :: grid_atom
    1348             :       TYPE(gto_basis_set_type), POINTER                  :: ri_basis
    1349             :       TYPE(harmonics_atom_type), POINTER                 :: harmonics
    1350          12 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
    1351          12 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
    1352             : 
    1353          12 :       NULLIFY (qs_kind_set, ri_basis, lmax, npgf, nsgf_set, lmin, zet, first_sgf, grid_atom)
    1354          12 :       NULLIFY (harmonics, rhoa, rhob, particle_set, cell, ri_sphi)
    1355             : 
    1356             :       !Same logic as the  put_density_on_own_grid routine. Loop over orbitals, put them on the grid,
    1357             :       !contract into sgf and daxpy with coeff. Notable difference: use cartesian orbitals instead of
    1358             :       !spherical, since the center of the grid is not the origin and thus, spherical symmetry can't
    1359             :       !be exploited so well
    1360             : 
    1361          12 :       CALL timeset(routineN, handle)
    1362             : 
    1363             :       !Generalities
    1364          12 :       CALL get_qs_env(qs_env, qs_kind_set=qs_kind_set, particle_set=particle_set, cell=cell)
    1365             :       !want basis of the source atom
    1366          12 :       CALL get_qs_kind(qs_kind_set(source_ikind), basis_set=ri_basis, basis_type="RI_XAS")
    1367             :       CALL get_gto_basis_set(ri_basis, lmax=lmax, npgf=npgf, zet=zet, nset=nset, nsgf_set=nsgf_set, &
    1368          12 :                              first_sgf=first_sgf, lmin=lmin, sphi=ri_sphi)
    1369             : 
    1370             :       ! Want the grid and harmonics of the target atom
    1371          12 :       grid_atom => xas_atom_env%grid_atom_set(target_ikind)%grid_atom
    1372          12 :       harmonics => xas_atom_env%harmonics_atom_set(target_ikind)%harmonics_atom
    1373          12 :       na = grid_atom%ng_sphere
    1374          12 :       nr = er - sr + 1
    1375          12 :       n = na*nr
    1376          12 :       nspins = xas_atom_env%nspins
    1377             : 
    1378             :       !  Point to the rho_set densities
    1379          12 :       rhoa => rho_set%rhoa
    1380          12 :       rhob => rho_set%rhob
    1381             : 
    1382             :       !  Need the source-target position vector
    1383          12 :       rs = pbc(particle_set(source_iat)%r, cell)
    1384          12 :       rt = pbc(particle_set(target_iat)%r, cell)
    1385          12 :       rst = pbc(rs, rt, cell)
    1386             : 
    1387             :       ! Precompute the positions on the target grid
    1388          60 :       ALLOCATE (pos(na, sr:er, 4))
    1389             : !$OMP PARALLEL DO COLLAPSE(2) SCHEDULE(STATIC) DEFAULT(NONE), &
    1390             : !$OMP SHARED(na,sr,er,pos,harmonics,grid_atom,rst), &
    1391          12 : !$OMP PRIVATE(ia,ir)
    1392             :       DO ir = sr, er
    1393             :          DO ia = 1, na
    1394             :             pos(ia, ir, 1:3) = harmonics%a(:, ia)*grid_atom%rad(ir) + rst
    1395             :             pos(ia, ir, 4) = pos(ia, ir, 1)**2 + pos(ia, ir, 2)**2 + pos(ia, ir, 3)**2
    1396             :          END DO
    1397             :       END DO
    1398             : !$OMP END PARALLEL DO
    1399             : 
    1400             :       ! Loop over the cartesian gaussian functions and evaluate them
    1401          36 :       DO iset = 1, nset
    1402             : 
    1403             :          !allocate space to store the cartesian orbtial on the grid
    1404         120 :          ALLOCATE (co(na, sr:er, npgf(iset)*ncoset(lmax(iset))))
    1405         144 :          IF (do_gga) ALLOCATE (dco(na, sr:er, 3, npgf(iset)*ncoset(lmax(iset))))
    1406             : 
    1407             : !$OMP PARALLEL DEFAULT(NONE), &
    1408             : !$OMP SHARED(co,npgf,ncoset,lmax,lmin,indco,pos,zet,iset,na,sr,er,do_gga,dco), &
    1409          24 : !$OMP PRIVATE(ipgf,start,ico,lx,ly,lz,ia,ir,rmom)
    1410             : 
    1411             : !$OMP DO COLLAPSE(2) SCHEDULE(STATIC)
    1412             :          DO ir = sr, er
    1413             :             DO ia = 1, na
    1414             :                co(ia, ir, :) = 0.0_dp
    1415             :                IF (do_gga) THEN
    1416             :                   dco(ia, ir, :, :) = 0.0_dp
    1417             :                END IF
    1418             :             END DO
    1419             :          END DO
    1420             : !$OMP END DO NOWAIT
    1421             : 
    1422             :          DO ipgf = 1, npgf(iset)
    1423             :             start = (ipgf - 1)*ncoset(lmax(iset))
    1424             : 
    1425             :             !loop over the cartesian orbitals
    1426             :             DO ico = ncoset(lmin(iset) - 1) + 1, ncoset(lmax(iset))
    1427             :                lx = indco(1, ico)
    1428             :                ly = indco(2, ico)
    1429             :                lz = indco(3, ico)
    1430             : 
    1431             :                ! compute g = x**lx * y**ly * z**lz * exp(-zet * r**2)
    1432             : !$OMP DO COLLAPSE(2) SCHEDULE(STATIC)
    1433             :                DO ir = sr, er
    1434             :                   DO ia = 1, na
    1435             :                      rmom = EXP(-zet(ipgf, iset)*pos(ia, ir, 4))
    1436             :                      IF (lx /= 0) rmom = rmom*pos(ia, ir, 1)**lx
    1437             :                      IF (ly /= 0) rmom = rmom*pos(ia, ir, 2)**ly
    1438             :                      IF (lz /= 0) rmom = rmom*pos(ia, ir, 3)**lz
    1439             :                      co(ia, ir, start + ico) = rmom
    1440             :                      !co(ia, ir, start + ico) = pos(ia, ir, 1)**lx*pos(ia, ir, 2)**ly*pos(ia, ir, 3)**lz &
    1441             :                      !                          *EXP(-zet(ipgf, iset)*pos(ia, ir, 4))
    1442             :                   END DO
    1443             :                END DO
    1444             : !$OMP END DO NOWAIT
    1445             : 
    1446             :                IF (do_gga) THEN
    1447             :                   !the gradient: dg_x = lx*x**(lx-1) * y**ly * z**lz * exp(-zet * r**2)
    1448             :                   !                     -2*zet* x**(lx+1) * y**ly * z**lz * exp(-zet * r**2)
    1449             :                   !                   = (lx*x**(lx-1) - 2*zet*x**(lx+1)) * y**ly * z**lz * exp(-zet * r**2)
    1450             : 
    1451             :                   !x direction, special case if lx == 0
    1452             :                   IF (lx == 0) THEN
    1453             : !$OMP DO COLLAPSE(2) SCHEDULE(STATIC)
    1454             :                      DO ir = sr, er
    1455             :                         DO ia = 1, na
    1456             :                            rmom = -2.0_dp*pos(ia, ir, 1)*zet(ipgf, iset)*EXP(-zet(ipgf, iset)*pos(ia, ir, 4))
    1457             :                            IF (ly /= 0) rmom = rmom*pos(ia, ir, 2)**ly
    1458             :                            IF (lz /= 0) rmom = rmom*pos(ia, ir, 3)**lz
    1459             :                            dco(ia, ir, 1, start + ico) = rmom
    1460             : !                          dco(ia, ir, 1, start + ico) = -2.0_dp*pos(ia, ir, 1)*zet(ipgf, iset) &
    1461             : !                                                        *pos(ia, ir, 2)**ly*pos(ia, ir, 3)**lz &
    1462             : !                                                        *EXP(-zet(ipgf, iset)*pos(ia, ir, 4))
    1463             :                         END DO
    1464             :                      END DO
    1465             : !$OMP END DO NOWAIT
    1466             :                   ELSE
    1467             : !$OMP DO COLLAPSE(2) SCHEDULE(STATIC)
    1468             :                      DO ir = sr, er
    1469             :                         DO ia = 1, na
    1470             :                            IF (lx /= 1) THEN
    1471             :                               rmom = (lx*pos(ia, ir, 1)**(lx - 1) - 2.0_dp*pos(ia, ir, 1)**(lx + 1)* &
    1472             :                                       zet(ipgf, iset))*EXP(-zet(ipgf, iset)*pos(ia, ir, 4))
    1473             :                            ELSE
    1474             :                               rmom = (1.0_dp - 2.0_dp*pos(ia, ir, 1)**2*zet(ipgf, iset))* &
    1475             :                                      EXP(-zet(ipgf, iset)*pos(ia, ir, 4))
    1476             :                            END IF
    1477             :                            IF (ly /= 0) rmom = rmom*pos(ia, ir, 2)**ly
    1478             :                            IF (lz /= 0) rmom = rmom*pos(ia, ir, 3)**lz
    1479             :                            dco(ia, ir, 1, start + ico) = rmom
    1480             : !                          dco(ia, ir, 1, start + ico) = (lx*pos(ia, ir, 1)**(lx - 1) &
    1481             : !                                                         - 2.0_dp*pos(ia, ir, 1)**(lx + 1)*zet(ipgf, iset)) &
    1482             : !                                                        *pos(ia, ir, 2)**ly*pos(ia, ir, 3)**lz &
    1483             : !                                                        *EXP(-zet(ipgf, iset)*pos(ia, ir, 4))
    1484             :                         END DO
    1485             :                      END DO
    1486             : !$OMP END DO NOWAIT
    1487             :                   END IF !lx == 0
    1488             : 
    1489             :                   !y direction, special case if ly == 0
    1490             :                   IF (ly == 0) THEN
    1491             : !$OMP DO COLLAPSE(2) SCHEDULE(STATIC)
    1492             :                      DO ir = sr, er
    1493             :                         DO ia = 1, na
    1494             :                            rmom = -2.0_dp*pos(ia, ir, 2)*zet(ipgf, iset)*EXP(-zet(ipgf, iset)*pos(ia, ir, 4))
    1495             :                            IF (lx /= 0) rmom = rmom*pos(ia, ir, 1)**lx
    1496             :                            IF (lz /= 0) rmom = rmom*pos(ia, ir, 3)**lz
    1497             :                            dco(ia, ir, 2, start + ico) = rmom
    1498             : !                          dco(ia, ir, 2, start + ico) = -2.0_dp*pos(ia, ir, 2)*zet(ipgf, iset) &
    1499             : !                                                        *pos(ia, ir, 1)**lx*pos(ia, ir, 3)**lz &
    1500             : !                                                        *EXP(-zet(ipgf, iset)*pos(ia, ir, 4))
    1501             :                         END DO
    1502             :                      END DO
    1503             : !$OMP END DO NOWAIT
    1504             :                   ELSE
    1505             : !$OMP DO COLLAPSE(2) SCHEDULE(STATIC)
    1506             :                      DO ir = sr, er
    1507             :                         DO ia = 1, na
    1508             :                            IF (ly /= 1) THEN
    1509             :                               rmom = (ly*pos(ia, ir, 2)**(ly - 1) - 2.0_dp*pos(ia, ir, 2)**(ly + 1)*zet(ipgf, iset)) &
    1510             :                                      *EXP(-zet(ipgf, iset)*pos(ia, ir, 4))
    1511             :                            ELSE
    1512             :                               rmom = (1.0_dp - 2.0_dp*pos(ia, ir, 2)**2*zet(ipgf, iset)) &
    1513             :                                      *EXP(-zet(ipgf, iset)*pos(ia, ir, 4))
    1514             :                            END IF
    1515             :                            IF (lx /= 0) rmom = rmom*pos(ia, ir, 1)**lx
    1516             :                            IF (lz /= 0) rmom = rmom*pos(ia, ir, 3)**lz
    1517             :                            dco(ia, ir, 2, start + ico) = rmom
    1518             : !                          dco(ia, ir, 2, start + ico) = (ly*pos(ia, ir, 2)**(ly - 1) &
    1519             : !                                                         - 2.0_dp*pos(ia, ir, 2)**(ly + 1)*zet(ipgf, iset)) &
    1520             : !                                                        *pos(ia, ir, 1)**lx*pos(ia, ir, 3)**lz &
    1521             : !                                                        *EXP(-zet(ipgf, iset)*pos(ia, ir, 4))
    1522             :                         END DO
    1523             :                      END DO
    1524             : !$OMP END DO NOWAIT
    1525             :                   END IF !ly == 0
    1526             : 
    1527             :                   !z direction, special case if lz == 0
    1528             :                   IF (lz == 0) THEN
    1529             : !$OMP DO COLLAPSE(2) SCHEDULE(STATIC)
    1530             :                      DO ir = sr, er
    1531             :                         DO ia = 1, na
    1532             :                            rmom = -2.0_dp*pos(ia, ir, 3)*zet(ipgf, iset)*EXP(-zet(ipgf, iset)*pos(ia, ir, 4))
    1533             :                            IF (lx /= 0) rmom = rmom*pos(ia, ir, 1)**lx
    1534             :                            IF (ly /= 0) rmom = rmom*pos(ia, ir, 2)**ly
    1535             :                            dco(ia, ir, 3, start + ico) = rmom
    1536             : !                          dco(ia, ir, 3, start + ico) = -2.0_dp*pos(ia, ir, 3)*zet(ipgf, iset) &
    1537             : !                                                        *pos(ia, ir, 1)**lx*pos(ia, ir, 2)**ly &
    1538             : !                                                        *EXP(-zet(ipgf, iset)*pos(ia, ir, 4))
    1539             :                         END DO
    1540             :                      END DO
    1541             : !$OMP END DO NOWAIT
    1542             :                   ELSE
    1543             : !$OMP DO COLLAPSE(2) SCHEDULE(STATIC)
    1544             :                      DO ir = sr, er
    1545             :                         DO ia = 1, na
    1546             :                            IF (lz /= 1) THEN
    1547             :                               rmom = (lz*pos(ia, ir, 3)**(lz - 1) - 2.0_dp*pos(ia, ir, 3)**(lz + 1)* &
    1548             :                                       zet(ipgf, iset))*EXP(-zet(ipgf, iset)*pos(ia, ir, 4))
    1549             :                            ELSE
    1550             :                               rmom = (1.0_dp - 2.0_dp*pos(ia, ir, 3)**2*zet(ipgf, iset))* &
    1551             :                                      EXP(-zet(ipgf, iset)*pos(ia, ir, 4))
    1552             :                            END IF
    1553             :                            IF (lx /= 0) rmom = rmom*pos(ia, ir, 1)**lx
    1554             :                            IF (ly /= 0) rmom = rmom*pos(ia, ir, 2)**ly
    1555             :                            dco(ia, ir, 3, start + ico) = rmom
    1556             : !                          dco(ia, ir, 3, start + ico) = (lz*pos(ia, ir, 3)**(lz - 1) &
    1557             : !                                                         - 2.0_dp*pos(ia, ir, 3)**(lz + 1)*zet(ipgf, iset)) &
    1558             : !                                                        *pos(ia, ir, 1)**lx*pos(ia, ir, 2)**ly &
    1559             : !                                                        *EXP(-zet(ipgf, iset)*pos(ia, ir, 4))
    1560             :                         END DO
    1561             :                      END DO
    1562             : !$OMP END DO NOWAIT
    1563             :                   END IF !lz == 0
    1564             : 
    1565             :                END IF !gga
    1566             : 
    1567             :             END DO !ico
    1568             :          END DO !ipgf
    1569             : 
    1570             : !$OMP END PARALLEL
    1571             : 
    1572             :          !contract the co into sgf
    1573          96 :          ALLOCATE (sgf(na, sr:er))
    1574         120 :          IF (do_gga) ALLOCATE (dsgf(na, sr:er, 3))
    1575          24 :          sgfi = first_sgf(1, iset) - 1
    1576             : 
    1577         362 :          DO isgf = 1, nsgf_set(iset)
    1578    14897939 :             sgf = 0.0_dp
    1579    44694493 :             IF (do_gga) dsgf = 0.0_dp
    1580             : 
    1581        2632 :             DO ipgf = 1, npgf(iset)
    1582        2294 :                start = (ipgf - 1)*ncoset(lmax(iset))
    1583       21546 :                DO ico = ncoset(lmin(iset) - 1) + 1, ncoset(lmax(iset))
    1584       21208 :                   CALL daxpy(n, ri_sphi(start + ico, sgfi + isgf), co(:, sr:er, start + ico), 1, sgf(:, sr:er), 1)
    1585             :                END DO !ico
    1586             :             END DO !ipgf
    1587             : 
    1588             :             !add the density to the grid
    1589         338 :             CALL daxpy(n, ri_dcoeff(1)%array(sgfi + isgf), sgf(:, sr:er), 1, rhoa(:, sr:er, 1), 1)
    1590             : 
    1591         338 :             IF (nspins == 2) THEN
    1592         138 :                CALL daxpy(n, ri_dcoeff(2)%array(sgfi + isgf), sgf(:, sr:er), 1, rhob(:, sr:er, 1), 1)
    1593             :             END IF
    1594             : 
    1595             :             !deal with the gradient
    1596         362 :             IF (do_gga) THEN
    1597             : 
    1598        2632 :                DO ipgf = 1, npgf(iset)
    1599        2294 :                   start = (ipgf - 1)*ncoset(lmax(iset))
    1600       21546 :                   DO ico = ncoset(lmin(iset) - 1) + 1, ncoset(lmax(iset))
    1601       77950 :                      DO dir = 1, 3
    1602             :                         CALL daxpy(n, ri_sphi(start + ico, sgfi + isgf), dco(:, sr:er, dir, start + ico), &
    1603       75656 :                                    1, dsgf(:, sr:er, dir), 1)
    1604             :                      END DO
    1605             :                   END DO !ico
    1606             :                END DO !ipgf
    1607             : 
    1608        1352 :                DO dir = 1, 3
    1609             :                   CALL daxpy(n, ri_dcoeff(1)%array(sgfi + isgf), dsgf(:, sr:er, dir), 1, &
    1610        1014 :                              rho_set%drhoa(dir)%array(:, sr:er, 1), 1)
    1611             : 
    1612        1352 :                   IF (nspins == 2) THEN
    1613             :                      CALL daxpy(n, ri_dcoeff(2)%array(sgfi + isgf), dsgf(:, sr:er, dir), 1, &
    1614         414 :                                 rho_set%drhob(dir)%array(:, sr:er, 1), 1)
    1615             :                   END IF
    1616             :                END DO
    1617             :             END IF !do_gga
    1618             : 
    1619             :          END DO !isgf
    1620             : 
    1621          24 :          DEALLOCATE (co, sgf)
    1622          36 :          IF (do_gga) DEALLOCATE (dco, dsgf)
    1623             :       END DO !iset
    1624             : 
    1625             :       !Treat spin-restricted case (copy alpha into beta)
    1626          12 :       IF (nspins == 1) THEN
    1627           6 :          CALL dcopy(n, rhoa(:, sr:er, 1), 1, rhob(:, sr:er, 1), 1)
    1628             : 
    1629           6 :          IF (do_gga) THEN
    1630          24 :             DO dir = 1, 3
    1631          24 :                CALL dcopy(n, rho_set%drhoa(dir)%array(:, sr:er, 1), 1, rho_set%drhob(dir)%array(:, sr:er, 1), 1)
    1632             :             END DO
    1633             :          END IF
    1634             :       END IF
    1635             : 
    1636          12 :       CALL timestop(handle)
    1637             : 
    1638          36 :    END SUBROUTINE put_density_on_other_grid
    1639             : 
    1640             : ! **************************************************************************************************
    1641             : !> \brief Computes the norm of the density gradient on the atomic grid
    1642             : !> \param rho_set ...
    1643             : !> \param atom_kind ...
    1644             : !> \param xas_atom_env ...
    1645             : !> \note GGA is assumed
    1646             : ! **************************************************************************************************
    1647          18 :    SUBROUTINE compute_norm_drho(rho_set, atom_kind, xas_atom_env)
    1648             : 
    1649             :       TYPE(xc_rho_set_type), INTENT(INOUT)               :: rho_set
    1650             :       INTEGER, INTENT(IN)                                :: atom_kind
    1651             :       TYPE(xas_atom_env_type), POINTER                   :: xas_atom_env
    1652             : 
    1653             :       INTEGER                                            :: dir, ia, ir, n, na, nr, nspins
    1654             : 
    1655          18 :       na = xas_atom_env%grid_atom_set(atom_kind)%grid_atom%ng_sphere
    1656          18 :       nr = xas_atom_env%grid_atom_set(atom_kind)%grid_atom%nr
    1657          18 :       n = na*nr
    1658          18 :       nspins = xas_atom_env%nspins
    1659             : 
    1660      525303 :       rho_set%norm_drhoa = 0.0_dp
    1661      525303 :       rho_set%norm_drhob = 0.0_dp
    1662      525303 :       rho_set%norm_drho = 0.0_dp
    1663             : 
    1664          72 :       DO dir = 1, 3
    1665        8007 :          DO ir = 1, nr
    1666     1575855 :             DO ia = 1, na
    1667             :                rho_set%norm_drhoa(ia, ir, 1) = rho_set%norm_drhoa(ia, ir, 1) &
    1668     1575801 :                                                + rho_set%drhoa(dir)%array(ia, ir, 1)**2
    1669             :             END DO !ia
    1670             :          END DO !ir
    1671             :       END DO !dir
    1672      525303 :       rho_set%norm_drhoa = SQRT(rho_set%norm_drhoa)
    1673             : 
    1674          18 :       IF (nspins == 1) THEN
    1675             :          !spin-restricted
    1676          16 :          CALL dcopy(n, rho_set%norm_drhoa(:, :, 1), 1, rho_set%norm_drhob(:, :, 1), 1)
    1677             :       ELSE
    1678           8 :          DO dir = 1, 3
    1679        1466 :             DO ir = 1, nr
    1680      441780 :                DO ia = 1, na
    1681             :                   rho_set%norm_drhob(ia, ir, 1) = rho_set%norm_drhob(ia, ir, 1) &
    1682      441774 :                                                   + rho_set%drhob(dir)%array(ia, ir, 1)**2
    1683             :                END DO
    1684             :             END DO
    1685             :          END DO
    1686      147262 :          rho_set%norm_drhob = SQRT(rho_set%norm_drhob)
    1687             :       END IF
    1688             : 
    1689          72 :       DO dir = 1, 3
    1690        8007 :          DO ir = 1, nr
    1691     1575855 :             DO ia = 1, na
    1692             :                rho_set%norm_drho(ia, ir, 1) = rho_set%norm_drho(ia, ir, 1) + &
    1693             :                                               (rho_set%drhoa(dir)%array(ia, ir, 1) + &
    1694     1575801 :                                                rho_set%drhob(dir)%array(ia, ir, 1))**2
    1695             :             END DO
    1696             :          END DO
    1697             :       END DO
    1698      525303 :       rho_set%norm_drho = SQRT(rho_set%norm_drho)
    1699             : 
    1700          18 :    END SUBROUTINE compute_norm_drho
    1701             : 
    1702             : ! **************************************************************************************************
    1703             : !> \brief Precomputes the spherical orbitals of the RI basis on the excited atom grids
    1704             : !> \param do_gga whether the gradient needs to be computed for GGA or not
    1705             : !> \param batch_info the parallelization info to complete with so distribution info
    1706             : !> \param xas_atom_env ...
    1707             : !> \param qs_env ...
    1708             : !> \note the functions are split in a purely angular part of size na and a purely radial part of
    1709             : !>       size nr. The full function on the grid can simply be obtained with dgemm and we save space
    1710             : ! **************************************************************************************************
    1711          38 :    SUBROUTINE precompute_so_dso(do_gga, batch_info, xas_atom_env, qs_env)
    1712             : 
    1713             :       LOGICAL, INTENT(IN)                                :: do_gga
    1714             :       TYPE(batch_info_type)                              :: batch_info
    1715             :       TYPE(xas_atom_env_type), POINTER                   :: xas_atom_env
    1716             :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1717             : 
    1718             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'precompute_so_dso'
    1719             : 
    1720             :       INTEGER                                            :: bo(2), dir, handle, ikind, ipgf, iset, &
    1721             :                                                             iso, iso_proc, l, maxso, n, na, nkind, &
    1722             :                                                             nr, nset, nso_proc, nsotot, starti
    1723          38 :       INTEGER, DIMENSION(:), POINTER                     :: lmax, lmin, npgf, nsgf_set
    1724          38 :       INTEGER, DIMENSION(:, :), POINTER                  :: so_proc_info
    1725          38 :       REAL(dp), ALLOCATABLE, DIMENSION(:)                :: rexp
    1726          38 :       REAL(dp), DIMENSION(:, :), POINTER                 :: dgr1, dgr2, ga, gr, slm, zet
    1727          38 :       REAL(dp), DIMENSION(:, :, :), POINTER              :: dga1, dga2, dslm_dxyz
    1728             :       TYPE(grid_atom_type), POINTER                      :: grid_atom
    1729             :       TYPE(gto_basis_set_type), POINTER                  :: ri_basis
    1730             :       TYPE(harmonics_atom_type), POINTER                 :: harmonics
    1731             :       TYPE(mp_para_env_type), POINTER                    :: para_env
    1732          38 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
    1733             : 
    1734          38 :       NULLIFY (qs_kind_set, harmonics, grid_atom, slm, dslm_dxyz, ri_basis, lmax, lmin, npgf)
    1735          38 :       NULLIFY (nsgf_set, zet, para_env, so_proc_info)
    1736             : 
    1737          38 :       CALL timeset(routineN, handle)
    1738             : 
    1739          38 :       CALL get_qs_env(qs_env, qs_kind_set=qs_kind_set, para_env=para_env)
    1740          38 :       nkind = SIZE(qs_kind_set)
    1741             : 
    1742         174 :       ALLOCATE (batch_info%so_proc_info(nkind))
    1743         114 :       ALLOCATE (batch_info%nso_proc(nkind))
    1744         114 :       ALLOCATE (batch_info%so_bo(2, nkind))
    1745             : 
    1746          98 :       DO ikind = 1, nkind
    1747             : 
    1748          60 :          NULLIFY (xas_atom_env%ga(ikind)%array)
    1749          60 :          NULLIFY (xas_atom_env%gr(ikind)%array)
    1750          60 :          NULLIFY (xas_atom_env%dga1(ikind)%array)
    1751          60 :          NULLIFY (xas_atom_env%dga2(ikind)%array)
    1752          60 :          NULLIFY (xas_atom_env%dgr1(ikind)%array)
    1753          60 :          NULLIFY (xas_atom_env%dgr2(ikind)%array)
    1754             : 
    1755          60 :          NULLIFY (batch_info%so_proc_info(ikind)%array)
    1756             : 
    1757          84 :          IF (.NOT. ANY(xas_atom_env%excited_kinds == ikind)) CYCLE
    1758             : 
    1759             :          !grid info
    1760          42 :          harmonics => xas_atom_env%harmonics_atom_set(ikind)%harmonics_atom
    1761          42 :          grid_atom => xas_atom_env%grid_atom_set(ikind)%grid_atom
    1762             : 
    1763          42 :          na = grid_atom%ng_sphere
    1764          42 :          nr = grid_atom%nr
    1765          42 :          n = na*nr
    1766             : 
    1767          42 :          slm => harmonics%slm
    1768          42 :          dslm_dxyz => harmonics%dslm_dxyz
    1769             : 
    1770             :          !basis info
    1771          42 :          CALL get_qs_kind(qs_kind_set(ikind), basis_set=ri_basis, basis_type="RI_XAS")
    1772             :          CALL get_gto_basis_set(ri_basis, lmax=lmax, npgf=npgf, zet=zet, nset=nset, &
    1773          42 :                                 nsgf_set=nsgf_set, lmin=lmin, maxso=maxso)
    1774          42 :          nsotot = maxso*nset
    1775             : 
    1776             :          !we split all so among the processors of the batch
    1777          42 :          bo = get_limit(nsotot, batch_info%batch_size, batch_info%ipe)
    1778          42 :          nso_proc = bo(2) - bo(1) + 1
    1779         126 :          batch_info%so_bo(:, ikind) = bo
    1780          42 :          batch_info%nso_proc(ikind) = nso_proc
    1781             : 
    1782             :          !store info about the so's set, pgf and index
    1783         126 :          ALLOCATE (batch_info%so_proc_info(ikind)%array(3, nso_proc))
    1784          42 :          so_proc_info => batch_info%so_proc_info(ikind)%array
    1785       17586 :          so_proc_info = -1 !default is -1 => set so value to zero
    1786         164 :          DO iset = 1, nset
    1787         838 :             DO ipgf = 1, npgf(iset)
    1788         674 :                starti = (iset - 1)*maxso + (ipgf - 1)*nsoset(lmax(iset))
    1789        4738 :                DO iso = nsoset(lmin(iset) - 1) + 1, nsoset(lmax(iset))
    1790             : 
    1791             :                   !only consider so that are on this proc
    1792        3942 :                   IF (starti + iso < bo(1) .OR. starti + iso > bo(2)) CYCLE
    1793        2442 :                   iso_proc = starti + iso - bo(1) + 1
    1794        2442 :                   so_proc_info(1, iso_proc) = iset
    1795        2442 :                   so_proc_info(2, iso_proc) = ipgf
    1796        4616 :                   so_proc_info(3, iso_proc) = iso
    1797             : 
    1798             :                END DO
    1799             :             END DO
    1800             :          END DO
    1801             : 
    1802             :          !Put the gaussians and their gradient as purely angular or radial arrays
    1803         168 :          ALLOCATE (xas_atom_env%ga(ikind)%array(na, nso_proc))
    1804         168 :          ALLOCATE (xas_atom_env%gr(ikind)%array(nr, nso_proc))
    1805     1440120 :          xas_atom_env%ga(ikind)%array = 0.0_dp; xas_atom_env%gr(ikind)%array = 0.0_dp
    1806          42 :          IF (do_gga) THEN
    1807         110 :             ALLOCATE (xas_atom_env%dga1(ikind)%array(na, nso_proc, 3))
    1808          66 :             ALLOCATE (xas_atom_env%dgr1(ikind)%array(nr, nso_proc))
    1809          66 :             ALLOCATE (xas_atom_env%dga2(ikind)%array(na, nso_proc, 3))
    1810          66 :             ALLOCATE (xas_atom_env%dgr2(ikind)%array(nr, nso_proc))
    1811     1752334 :             xas_atom_env%dga1(ikind)%array = 0.0_dp; xas_atom_env%dgr1(ikind)%array = 0.0_dp
    1812     1752334 :             xas_atom_env%dga2(ikind)%array = 0.0_dp; xas_atom_env%dgr2(ikind)%array = 0.0_dp
    1813             :          END IF
    1814             : 
    1815          42 :          ga => xas_atom_env%ga(ikind)%array
    1816          42 :          gr => xas_atom_env%gr(ikind)%array
    1817          42 :          dga1 => xas_atom_env%dga1(ikind)%array
    1818          42 :          dga2 => xas_atom_env%dga2(ikind)%array
    1819          42 :          dgr1 => xas_atom_env%dgr1(ikind)%array
    1820          42 :          dgr2 => xas_atom_env%dgr2(ikind)%array
    1821             : 
    1822         126 :          ALLOCATE (rexp(nr))
    1823             : 
    1824        4428 :          DO iso_proc = 1, nso_proc
    1825        4386 :             iset = so_proc_info(1, iso_proc)
    1826        4386 :             ipgf = so_proc_info(2, iso_proc)
    1827        4386 :             iso = so_proc_info(3, iso_proc)
    1828        4386 :             IF (iso < 0) CYCLE
    1829             : 
    1830        2442 :             l = indso(1, iso)
    1831             : 
    1832             :             !The gaussian is g = r^l * Ylm * exp(-a*r^2)
    1833             : 
    1834             :             !radial part of the gaussian
    1835      327717 :             rexp(1:nr) = EXP(-zet(ipgf, iset)*grid_atom%rad2(1:nr))
    1836      652992 :             gr(1:nr, iso_proc) = grid_atom%rad(1:nr)**l*rexp(1:nr)
    1837             : 
    1838             :             !angular part of the gaussian
    1839      859962 :             ga(1:na, iso_proc) = slm(1:na, iso)
    1840             : 
    1841             :             !For the gradient, devide in 2 parts: dg/dx = d/dx(r^l * Ylm) * exp(-a*r^2)
    1842             :             !                                            + r^l * Ylm *  d/dx(exp(-a*r^2))
    1843             :             !Note: we make this choice of separation because of cartesian coordinates, where
    1844             :             !      g = x^lx * y^ly * z^lz * exp(-a*r^2) and r^(l-1)*dslm_dxyz = d/dx(r^l * Ylm)
    1845             : 
    1846        2484 :             IF (do_gga) THEN
    1847             :                !radial part of the gradient => same in all three direction
    1848      444727 :                dgr1(1:nr, iso_proc) = grid_atom%rad(1:nr)**(l - 1)*rexp(1:nr)
    1849      444727 :                dgr2(1:nr, iso_proc) = -2.0_dp*zet(ipgf, iset)*grid_atom%rad(1:nr)**(l + 1)*rexp(1:nr)
    1850             : 
    1851             :                !angular part of the gradient
    1852        6188 :                DO dir = 1, 3
    1853     1630029 :                   dga1(1:na, iso_proc, dir) = dslm_dxyz(dir, 1:na, iso)
    1854     1631576 :                   dga2(1:na, iso_proc, dir) = harmonics%a(dir, 1:na)*slm(1:na, iso)
    1855             :                END DO
    1856             :             END IF
    1857             : 
    1858             :          END DO !iso_proc
    1859             : 
    1860         140 :          DEALLOCATE (rexp)
    1861             :       END DO !ikind
    1862             : 
    1863          38 :       CALL timestop(handle)
    1864             : 
    1865          76 :    END SUBROUTINE precompute_so_dso
    1866             : 
    1867             : ! **************************************************************************************************
    1868             : !> \brief Integrate the xc kernel as a function of r on the atomic grids for the RI_XAS basis
    1869             : !> \param int_fxc the global array containing the (P|fxc|Q) integrals, for all spin configurations
    1870             : !> \param xas_atom_env ...
    1871             : !> \param xas_tdp_control ...
    1872             : !> \param qs_env ...
    1873             : !> \note Note that if closed-shell, alpha-alpha term and beta-beta terms are the same
    1874             : !>       Store the (P|fxc|Q) integrals on the processor they were computed on
    1875             : !>       int_fxc(1)%matrix is alpha-alpha, 2: alpha-beta, 3: beta-beta
    1876             : ! **************************************************************************************************
    1877          38 :    SUBROUTINE integrate_fxc_atoms(int_fxc, xas_atom_env, xas_tdp_control, qs_env)
    1878             : 
    1879             :       TYPE(cp_2d_r_p_type), DIMENSION(:, :), POINTER     :: int_fxc
    1880             :       TYPE(xas_atom_env_type), POINTER                   :: xas_atom_env
    1881             :       TYPE(xas_tdp_control_type), POINTER                :: xas_tdp_control
    1882             :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1883             : 
    1884             :       CHARACTER(len=*), PARAMETER :: routineN = 'integrate_fxc_atoms'
    1885             : 
    1886             :       INTEGER :: batch_size, dir, er, ex_bo(2), handle, i, iatom, ibatch, iex, ikind, inb, ipe, &
    1887             :          mepos, na, natom, nb, nb_bo(2), nbatch, nbk, nex_atom, nr, num_pe, sr
    1888             :       INTEGER, DIMENSION(2, 3)                           :: bounds
    1889          38 :       INTEGER, DIMENSION(:), POINTER                     :: exat_neighbors
    1890             :       LOGICAL                                            :: do_gga, do_sc, do_sf
    1891          38 :       TYPE(batch_info_type)                              :: batch_info
    1892          38 :       TYPE(cp_1d_r_p_type), DIMENSION(:, :), POINTER     :: ri_dcoeff
    1893             :       TYPE(dft_control_type), POINTER                    :: dft_control
    1894             :       TYPE(mp_para_env_type), POINTER                    :: para_env
    1895          38 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
    1896          38 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
    1897             :       TYPE(section_vals_type), POINTER                   :: input, xc_functionals
    1898             :       TYPE(xc_derivative_set_type)                       :: deriv_set
    1899             :       TYPE(xc_rho_cflags_type)                           :: needs
    1900             :       TYPE(xc_rho_set_type)                              :: rho_set
    1901             : 
    1902          38 :       NULLIFY (particle_set, qs_kind_set, dft_control, para_env, exat_neighbors)
    1903          38 :       NULLIFY (input, xc_functionals)
    1904             : 
    1905          38 :       CALL timeset(routineN, handle)
    1906             : 
    1907             : !  Initialize
    1908             :       CALL get_qs_env(qs_env, particle_set=particle_set, qs_kind_set=qs_kind_set, natom=natom, &
    1909          38 :                       dft_control=dft_control, input=input, para_env=para_env)
    1910        1746 :       ALLOCATE (int_fxc(natom, 4))
    1911         408 :       DO iatom = 1, natom
    1912        1888 :          DO i = 1, 4
    1913        1850 :             NULLIFY (int_fxc(iatom, i)%array)
    1914             :          END DO
    1915             :       END DO
    1916          38 :       nex_atom = SIZE(xas_atom_env%excited_atoms)
    1917             :       !spin conserving in the general sense here
    1918          38 :       do_sc = xas_tdp_control%do_spin_cons .OR. xas_tdp_control%do_singlet .OR. xas_tdp_control%do_triplet
    1919          38 :       do_sf = xas_tdp_control%do_spin_flip
    1920             : 
    1921             : !  Get some info on the functionals
    1922          38 :       xc_functionals => section_vals_get_subs_vals(input, "DFT%XAS_TDP%KERNEL%XC_FUNCTIONAL")
    1923             :       ! ask for lsd in any case
    1924          38 :       needs = xc_functionals_get_needs(xc_functionals, lsd=.TRUE., calc_potential=.TRUE.)
    1925          38 :       do_gga = needs%drho_spin !because either LDA or GGA, and the former does not need gradient
    1926             : 
    1927             : !  Distribute the excited atoms over batches of processors
    1928             : !  Then, the spherical orbital of the RI basis are distributed among the procs of the batch, making
    1929             : !  the GGA integration very efficient
    1930          38 :       num_pe = para_env%num_pe
    1931          38 :       mepos = para_env%mepos
    1932             : 
    1933             :       !create a batch_info_type
    1934          38 :       CALL get_proc_batch_sizes(batch_size, nbatch, nex_atom, num_pe)
    1935             : 
    1936             :       !the batch index
    1937          38 :       ibatch = mepos/batch_size
    1938             :       !the proc index within the batch
    1939          38 :       ipe = MODULO(mepos, batch_size)
    1940             : 
    1941          38 :       batch_info%batch_size = batch_size
    1942          38 :       batch_info%nbatch = nbatch
    1943          38 :       batch_info%ibatch = ibatch
    1944          38 :       batch_info%ipe = ipe
    1945             : 
    1946             :       !create a subcommunicator for this batch
    1947          38 :       CALL batch_info%para_env%from_split(para_env, ibatch)
    1948             : 
    1949             : !  Precompute the spherical orbital of the RI basis (and maybe their gradient) on the grids of the
    1950             : !  excited atoms. Needed for the GGA integration and to actually put the density on the grid
    1951          38 :       CALL precompute_so_dso(do_gga, batch_info, xas_atom_env, qs_env)
    1952             : 
    1953             :       !distribute the excted atoms over the batches
    1954          38 :       ex_bo = get_limit(nex_atom, nbatch, ibatch)
    1955             : 
    1956             : !  Looping over the excited atoms
    1957          76 :       DO iex = ex_bo(1), ex_bo(2)
    1958             : 
    1959          38 :          iatom = xas_atom_env%excited_atoms(iex)
    1960          38 :          ikind = particle_set(iatom)%atomic_kind%kind_number
    1961          38 :          exat_neighbors => xas_atom_env%exat_neighbors(iex)%array
    1962          38 :          ri_dcoeff => xas_atom_env%ri_dcoeff(:, :, iex)
    1963             : 
    1964             : !     General grid/basis info
    1965          38 :          na = xas_atom_env%grid_atom_set(ikind)%grid_atom%ng_sphere
    1966          38 :          nr = xas_atom_env%grid_atom_set(ikind)%grid_atom%nr
    1967             : 
    1968             : !     Creating a xc_rho_set to store the density and dset for the kernel
    1969         380 :          bounds(1:2, 1:3) = 1
    1970          38 :          bounds(2, 1) = na
    1971          38 :          bounds(2, 2) = nr
    1972             : 
    1973             :          CALL xc_rho_set_create(rho_set=rho_set, local_bounds=bounds, &
    1974             :                                 rho_cutoff=dft_control%qs_control%eps_rho_rspace, &
    1975          38 :                                 drho_cutoff=dft_control%qs_control%eps_rho_rspace)
    1976          38 :          CALL xc_dset_create(deriv_set, local_bounds=bounds)
    1977             : 
    1978             :          ! allocate internals of the rho_set
    1979          38 :          CALL xc_rho_set_atom_update(rho_set, needs, nspins=2, bo=bounds)
    1980             : 
    1981             : !     Put the density, and possibly its gradient,  on the grid (for this atom)
    1982             :          CALL put_density_on_atomic_grid(rho_set, ri_dcoeff(iatom, :), ikind, &
    1983          38 :                                          do_gga, batch_info, xas_atom_env, qs_env)
    1984             : 
    1985             : !     Take the neighboring atom contributions to the density (and gradient)
    1986             : !     distribute the grid among the procs (for best load balance)
    1987          38 :          nb_bo = get_limit(nr, batch_size, ipe)
    1988          38 :          sr = nb_bo(1); er = nb_bo(2)
    1989          50 :          DO inb = 1, SIZE(exat_neighbors)
    1990             : 
    1991          12 :             nb = exat_neighbors(inb)
    1992          12 :             nbk = particle_set(nb)%atomic_kind%kind_number
    1993             :             CALL put_density_on_other_grid(rho_set, ri_dcoeff(nb, :), nb, nbk, iatom, &
    1994          50 :                                            ikind, sr, er, do_gga, xas_atom_env, qs_env)
    1995             : 
    1996             :          END DO
    1997             : 
    1998             :          ! make sure contributions from different procs are summed up
    1999          38 :          CALL batch_info%para_env%sum(rho_set%rhoa)
    2000          38 :          CALL batch_info%para_env%sum(rho_set%rhob)
    2001          38 :          IF (do_gga) THEN
    2002          72 :             DO dir = 1, 3
    2003          54 :                CALL batch_info%para_env%sum(rho_set%drhoa(dir)%array)
    2004          72 :                CALL batch_info%para_env%sum(rho_set%drhob(dir)%array)
    2005             :             END DO
    2006             :          END IF
    2007             : 
    2008             : !     In case of GGA, also need the norm of the density gradient
    2009          38 :          IF (do_gga) CALL compute_norm_drho(rho_set, ikind, xas_atom_env)
    2010             : 
    2011             : !     Compute the required derivatives
    2012             :          CALL xc_functionals_eval(xc_functionals, lsd=.TRUE., rho_set=rho_set, deriv_set=deriv_set, &
    2013          38 :                                   deriv_order=2)
    2014             : 
    2015             :          !spin-conserving (LDA part)
    2016          38 :          IF (do_sc) THEN
    2017          38 :             CALL integrate_sc_fxc(int_fxc, iatom, ikind, deriv_set, xas_atom_env, qs_env)
    2018             :          END IF
    2019             : 
    2020             :          !spin-flip (LDA part)
    2021          38 :          IF (do_sf) THEN
    2022           0 :             CALL integrate_sf_fxc(int_fxc, iatom, ikind, rho_set, deriv_set, xas_atom_env, qs_env)
    2023             :          END IF
    2024             : 
    2025             :          !Gradient correction (note: spin-flip only keeps the lda part, aka ALDA0)
    2026          38 :          IF (do_gga .AND. do_sc) THEN
    2027             :             CALL integrate_gga_fxc(int_fxc, iatom, ikind, batch_info, rho_set, deriv_set, &
    2028          18 :                                    xas_atom_env, qs_env)
    2029             :          END IF
    2030             : 
    2031             : !     Clean-up
    2032          38 :          CALL xc_dset_release(deriv_set)
    2033         114 :          CALL xc_rho_set_release(rho_set)
    2034             :       END DO !iex
    2035             : 
    2036          38 :       CALL release_batch_info(batch_info)
    2037             : 
    2038             :       !Not necessary to sync, but makes sure that any load inbalance is reported here
    2039          38 :       CALL para_env%sync()
    2040             : 
    2041          38 :       CALL timestop(handle)
    2042             : 
    2043         912 :    END SUBROUTINE integrate_fxc_atoms
    2044             : 
    2045             : ! **************************************************************************************************
    2046             : !> \brief Integrate the gradient correction part of the xc kernel on the atomic grid
    2047             : !> \param int_fxc the array containing the (P|fxc|Q) integrals
    2048             : !> \param iatom the index of the current excited atom
    2049             : !> \param ikind the index of the current excited kind
    2050             : !> \param batch_info how the so are distributed over the processor batch
    2051             : !> \param rho_set the variable contatinind the density and its gradient
    2052             : !> \param deriv_set the functional derivatives
    2053             : !> \param xas_atom_env ...
    2054             : !> \param qs_env ...
    2055             : !> \note Ignored in case of pure LDA, added on top of the LDA kernel in case of GGA
    2056             : ! **************************************************************************************************
    2057          18 :    SUBROUTINE integrate_gga_fxc(int_fxc, iatom, ikind, batch_info, rho_set, deriv_set, &
    2058             :                                 xas_atom_env, qs_env)
    2059             : 
    2060             :       TYPE(cp_2d_r_p_type), DIMENSION(:, :), POINTER     :: int_fxc
    2061             :       INTEGER, INTENT(IN)                                :: iatom, ikind
    2062             :       TYPE(batch_info_type)                              :: batch_info
    2063             :       TYPE(xc_rho_set_type), INTENT(IN)                  :: rho_set
    2064             :       TYPE(xc_derivative_set_type), INTENT(INOUT)        :: deriv_set
    2065             :       TYPE(xas_atom_env_type), POINTER                   :: xas_atom_env
    2066             :       TYPE(qs_environment_type), POINTER                 :: qs_env
    2067             : 
    2068             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'integrate_gga_fxc'
    2069             : 
    2070             :       INTEGER                                            :: bo(2), dir, handle, i, ia, ir, jpgf, &
    2071             :                                                             jset, jso, l, maxso, na, nr, nset, &
    2072             :                                                             nsgf, nsoi, nsotot, startj, ub
    2073          18 :       INTEGER, DIMENSION(:), POINTER                     :: lmax, lmin, npgf
    2074          18 :       REAL(dp), ALLOCATABLE, DIMENSION(:)                :: rexp
    2075          18 :       REAL(dp), ALLOCATABLE, DIMENSION(:, :)             :: int_sgf, res, so, work
    2076          18 :       REAL(dp), ALLOCATABLE, DIMENSION(:, :, :)          :: dso
    2077          18 :       REAL(dp), DIMENSION(:, :), POINTER                 :: dgr1, dgr2, ga, gr, ri_sphi_so, weight, &
    2078          18 :                                                             zet
    2079          18 :       REAL(dp), DIMENSION(:, :, :), POINTER              :: dga1, dga2
    2080          18 :       TYPE(cp_2d_r_p_type), ALLOCATABLE, DIMENSION(:)    :: int_so, vxc
    2081             :       TYPE(cp_3d_r_p_type), ALLOCATABLE, DIMENSION(:)    :: vxg
    2082             :       TYPE(grid_atom_type), POINTER                      :: grid_atom
    2083             :       TYPE(gto_basis_set_type), POINTER                  :: ri_basis
    2084             :       TYPE(harmonics_atom_type), POINTER                 :: harmonics
    2085             :       TYPE(mp_para_env_type), POINTER                    :: para_env
    2086          18 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
    2087             : 
    2088          18 :       NULLIFY (grid_atom, ri_basis, qs_kind_set, ga, gr, dgr1, dgr2, lmax, lmin, npgf)
    2089          18 :       NULLIFY (weight, ri_sphi_so, dga1, dga2, para_env, harmonics, zet)
    2090             : 
    2091             :       !Strategy: we need to compute <phi_i|fxc|phij>, most of existing application of the 2nd
    2092             :       !          functional derivative involve the response density, and the expression of the
    2093             :       !          integral int (fxc*n^1) is well known. We substitute the spherical orbital phi_j
    2094             :       !          in place of n^1 in the formula and thus perform the first integration. Then
    2095             :       !          we obtain something in the form int (fxc*phi_j) = Vxc - div (Vxg) that we can
    2096             :       !          put on the grid and treat like a potential. The second integration is done by
    2097             :       !          using the divergence theorem and numerical integration:
    2098             :       !          <phi_i|fxc|phi_j> = int phi_i*(Vxc - div(Vxg)) = int phi_i*Vxc + grad(phi_i).Vxg
    2099             :       !          Note the sign change and the dot product.
    2100             : 
    2101          18 :       CALL timeset(routineN, handle)
    2102             : 
    2103             :       !If closed shell, only compute f_aa and f_ab (ub = 2)
    2104          18 :       ub = 2
    2105          18 :       IF (xas_atom_env%nspins == 2) ub = 3
    2106             : 
    2107             :       !Get the necessary grid info
    2108          18 :       harmonics => xas_atom_env%harmonics_atom_set(ikind)%harmonics_atom
    2109          18 :       grid_atom => xas_atom_env%grid_atom_set(ikind)%grid_atom
    2110          18 :       na = grid_atom%ng_sphere
    2111          18 :       nr = grid_atom%nr
    2112          18 :       weight => grid_atom%weight
    2113             : 
    2114             :       !get the ri_basis info
    2115          18 :       CALL get_qs_env(qs_env, qs_kind_set=qs_kind_set, para_env=para_env)
    2116          18 :       CALL get_qs_kind(qs_kind_set(ikind), basis_set=ri_basis, basis_type="RI_XAS")
    2117             : 
    2118             :       CALL get_gto_basis_set(gto_basis_set=ri_basis, lmax=lmax, lmin=lmin, nsgf=nsgf, &
    2119          18 :                              maxso=maxso, npgf=npgf, nset=nset, zet=zet)
    2120          18 :       nsotot = nset*maxso
    2121             : 
    2122             :       !Point to the precomputed so
    2123          18 :       ga => xas_atom_env%ga(ikind)%array
    2124          18 :       gr => xas_atom_env%gr(ikind)%array
    2125          18 :       dgr1 => xas_atom_env%dgr1(ikind)%array
    2126          18 :       dgr2 => xas_atom_env%dgr2(ikind)%array
    2127          18 :       dga1 => xas_atom_env%dga1(ikind)%array
    2128          18 :       dga2 => xas_atom_env%dga2(ikind)%array
    2129             : 
    2130             :       !Before integration, wanna pre-divide all relevant derivastives by the nrom of the gradient
    2131          18 :       CALL divide_by_norm_drho(deriv_set, rho_set, lsd=.TRUE.)
    2132             : 
    2133             :       !Wanna integrate <phi_i|fxc|phi_j>, start looping over phi_j and do the first integration, then
    2134             :       !collect vxc and vxg and loop over phi_i for the second integration
    2135             :       !Note: we do not use the CG coefficients because they are only useful when there is a product
    2136             :       !      of Gaussians, which is not really the case here
    2137             :       !Note: the spherical orbitals for phi_i are distributed among the prcos of the current batch
    2138             : 
    2139          72 :       ALLOCATE (so(na, nr))
    2140          90 :       ALLOCATE (dso(na, nr, 3))
    2141          54 :       ALLOCATE (rexp(nr))
    2142             : 
    2143          74 :       ALLOCATE (vxc(ub))
    2144          56 :       ALLOCATE (vxg(ub))
    2145          56 :       ALLOCATE (int_so(ub))
    2146          56 :       DO i = 1, ub
    2147         114 :          ALLOCATE (vxc(i)%array(na, nr))
    2148         114 :          ALLOCATE (vxg(i)%array(na, nr, 3))
    2149         152 :          ALLOCATE (int_so(i)%array(nsotot, nsotot))
    2150     6342734 :          vxc(i)%array = 0.0_dp; vxg(i)%array = 0.0_dp; int_so(i)%array = 0.0_dp
    2151             :       END DO
    2152             : 
    2153          54 :       DO jset = 1, nset
    2154         312 :          DO jpgf = 1, npgf(jset)
    2155         258 :             startj = (jset - 1)*maxso + (jpgf - 1)*nsoset(lmax(jset))
    2156        2300 :             DO jso = nsoset(lmin(jset) - 1) + 1, nsoset(lmax(jset))
    2157        2006 :                l = indso(1, jso)
    2158             : 
    2159             :                !put the so phi_j and its gradient on the grid
    2160             :                !more efficient to recompute it rather than mp_bcast each chunk
    2161             : 
    2162      300685 :                rexp(1:nr) = EXP(-zet(jpgf, jset)*grid_atom%rad2(1:nr))
    2163             : !$OMP PARALLEL DO COLLAPSE(2) DEFAULT(NONE), &
    2164             : !$OMP SHARED(nr,na,so,dso,grid_atom,l,rexp,harmonics,jso,zet,jset,jpgf), &
    2165        2006 : !$OMP PRIVATE(ir,ia,dir)
    2166             :                DO ir = 1, nr
    2167             :                   DO ia = 1, na
    2168             : 
    2169             :                      !so
    2170             :                      so(ia, ir) = grid_atom%rad(ir)**l*rexp(ir)*harmonics%slm(ia, jso)
    2171             : 
    2172             :                      !dso
    2173             :                      dso(ia, ir, :) = 0.0_dp
    2174             :                      DO dir = 1, 3
    2175             :                         dso(ia, ir, dir) = dso(ia, ir, dir) &
    2176             :                                            + grid_atom%rad(ir)**(l - 1)*rexp(ir)*harmonics%dslm_dxyz(dir, ia, jso) &
    2177             :                                            - 2.0_dp*zet(jpgf, jset)*grid_atom%rad(ir)**(l + 1)*rexp(ir) &
    2178             :                                            *harmonics%a(dir, ia)*harmonics%slm(ia, jso)
    2179             :                      END DO
    2180             :                   END DO
    2181             :                END DO
    2182             : !$OMP END PARALLEL DO
    2183             : 
    2184             :                !Perform the first integration (analytically)
    2185        2006 :                CALL get_vxc_vxg(vxc, vxg, so, dso, na, nr, rho_set, deriv_set, weight)
    2186             : 
    2187             :                !For a given phi_j, compute the second integration with all phi_i at once
    2188             :                !=> allows for efficient gemm to take place, especially since so are distributed
    2189        2006 :                nsoi = batch_info%nso_proc(ikind)
    2190        6018 :                bo = batch_info%so_bo(:, ikind)
    2191       14042 :                ALLOCATE (res(nsoi, nsoi), work(na, nsoi))
    2192    80897954 :                res = 0.0_dp; work = 0.0_dp
    2193             : 
    2194        6270 :                DO i = 1, ub
    2195             : 
    2196             :                   !integrate so*Vxc and store in the int_so
    2197             :                   CALL dgemm('N', 'N', na, nsoi, nr, 1.0_dp, vxc(i)%array(:, :), na, &
    2198        4264 :                              gr(:, 1:nsoi), nr, 0.0_dp, work, na)
    2199             :                   CALL dgemm('T', 'N', nsoi, nsoi, na, 1.0_dp, work, na, &
    2200        4264 :                              ga(:, 1:nsoi), na, 0.0_dp, res, nsoi)
    2201      512884 :                   int_so(i)%array(bo(1):bo(2), startj + jso) = get_diag(res)
    2202             : 
    2203       19062 :                   DO dir = 1, 3
    2204             : 
    2205             :                      ! integrate and sum up Vxg*dso
    2206             :                      CALL dgemm('N', 'N', na, nsoi, nr, 1.0_dp, vxg(i)%array(:, :, dir), na, &
    2207       12792 :                                 dgr1(:, 1:nsoi), nr, 0.0_dp, work, na)
    2208             :                      CALL dgemm('T', 'N', nsoi, nsoi, na, 1.0_dp, work, na, &
    2209       12792 :                                 dga1(:, 1:nsoi, dir), na, 0.0_dp, res, nsoi)
    2210       12792 :                      CALL daxpy(nsoi, 1.0_dp, get_diag(res), 1, int_so(i)%array(bo(1):bo(2), startj + jso), 1)
    2211             : 
    2212             :                      CALL dgemm('N', 'N', na, nsoi, nr, 1.0_dp, vxg(i)%array(:, :, dir), na, &
    2213       12792 :                                 dgr2(:, 1:nsoi), nr, 0.0_dp, work, na)
    2214             :                      CALL dgemm('T', 'N', nsoi, nsoi, na, 1.0_dp, work, na, &
    2215       12792 :                                 dga2(:, 1:nsoi, dir), na, 0.0_dp, res, nsoi)
    2216       17056 :                      CALL daxpy(nsoi, 1.0_dp, get_diag(res), 1, int_so(i)%array(bo(1):bo(2), startj + jso), 1)
    2217             : 
    2218             :                   END DO
    2219             : 
    2220             :                END DO !i
    2221        2264 :                DEALLOCATE (res, work)
    2222             : 
    2223             :             END DO !jso
    2224             :          END DO !jpgf
    2225             :       END DO !jset
    2226             : 
    2227             :       !Contract into sgf and add to already computed LDA part of int_fxc
    2228          18 :       ri_sphi_so => xas_atom_env%ri_sphi_so(ikind)%array
    2229          72 :       ALLOCATE (int_sgf(nsgf, nsgf))
    2230          56 :       DO i = 1, ub
    2231     3102830 :          CALL batch_info%para_env%sum(int_so(i)%array)
    2232          38 :          CALL contract_so2sgf(int_sgf, int_so(i)%array, ri_basis, ri_sphi_so)
    2233          56 :          CALL daxpy(nsgf*nsgf, 1.0_dp, int_sgf, 1, int_fxc(iatom, i)%array, 1)
    2234             :       END DO
    2235             : 
    2236             :       !Clean-up
    2237          56 :       DO i = 1, ub
    2238          38 :          DEALLOCATE (vxc(i)%array)
    2239          38 :          DEALLOCATE (vxg(i)%array)
    2240          56 :          DEALLOCATE (int_so(i)%array)
    2241             :       END DO
    2242          18 :       DEALLOCATE (vxc, vxg, int_so)
    2243             : 
    2244          18 :       CALL timestop(handle)
    2245             : 
    2246          54 :    END SUBROUTINE integrate_gga_fxc
    2247             : 
    2248             : ! **************************************************************************************************
    2249             : !> \brief Computes the first integration of the GGA part of <phi_i|fxc|phi_j>, i.e. int fxc*phi_j.
    2250             : !>        The result is of the form Vxc - div(Vxg). Up to 3 results are returned, correspoinding to
    2251             : !>        f_aa, f_ab and (if open-shell) f_bb
    2252             : !> \param vxc ...
    2253             : !> \param vxg ...
    2254             : !> \param so the spherical orbital on the grid
    2255             : !> \param dso the derivative of the spherical orbital on the grid
    2256             : !> \param na ...
    2257             : !> \param nr ...
    2258             : !> \param rho_set ...
    2259             : !> \param deriv_set ...
    2260             : !> \param weight the grid weight
    2261             : !> \note This method is extremely similar to xc_calc_2nd_deriv of xc.F, but because it is a special
    2262             : !>       case that can be further optimized and because the interface of the original routine does
    2263             : !>       not fit this code, it has been re-written (no pw, no rho1_set but just the so, etc...)
    2264             : ! **************************************************************************************************
    2265        2006 :    SUBROUTINE get_vxc_vxg(vxc, vxg, so, dso, na, nr, rho_set, deriv_set, weight)
    2266             : 
    2267             :       TYPE(cp_2d_r_p_type), DIMENSION(:)                 :: vxc
    2268             :       TYPE(cp_3d_r_p_type), DIMENSION(:)                 :: vxg
    2269             :       REAL(dp), DIMENSION(:, :)                          :: so
    2270             :       REAL(dp), DIMENSION(:, :, :)                       :: dso
    2271             :       INTEGER, INTENT(IN)                                :: na, nr
    2272             :       TYPE(xc_rho_set_type), INTENT(IN)                  :: rho_set
    2273             :       TYPE(xc_derivative_set_type), INTENT(IN)           :: deriv_set
    2274             :       REAL(dp), DIMENSION(:, :), POINTER                 :: weight
    2275             : 
    2276             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'get_vxc_vxg'
    2277             : 
    2278             :       INTEGER                                            :: dir, handle, i, ia, ir, ub
    2279        2006 :       REAL(dp), ALLOCATABLE, DIMENSION(:, :)             :: dot_proda, dot_prodb, tmp
    2280        2006 :       REAL(dp), DIMENSION(:, :, :), POINTER              :: d1e, d2e, norm_drhoa, norm_drhob
    2281             :       TYPE(xc_derivative_type), POINTER                  :: deriv
    2282             : 
    2283        2006 :       NULLIFY (norm_drhoa, norm_drhob, d2e, d1e, deriv)
    2284             : 
    2285        2006 :       CALL timeset(routineN, handle)
    2286             : 
    2287             :       !Note: this routines follows the order of the terms in equaiton (A.7) of Thomas Chassaing
    2288             :       !      thesis, except for the pure LDA terms that are dropped. The n^(1)_a and n^(1)_b
    2289             :       !      response densities are replaced by the spherical orbital.
    2290             :       !      The usual spin ordering is used: aa => 1, ab => 2 , bb => 3
    2291             : 
    2292             :       !point to the relevant components of rho_set
    2293        2006 :       ub = SIZE(vxc)
    2294        2006 :       norm_drhoa => rho_set%norm_drhoa
    2295        2006 :       norm_drhob => rho_set%norm_drhob
    2296             : 
    2297             :       !Some init
    2298        6270 :       DO i = 1, ub
    2299   141677782 :          vxc(i)%array = 0.0_dp
    2300   425039616 :          vxg(i)%array = 0.0_dp
    2301             :       END DO
    2302             : 
    2303       16048 :       ALLOCATE (tmp(na, nr), dot_proda(na, nr), dot_prodb(na, nr))
    2304   123123022 :       dot_proda = 0.0_dp; dot_prodb = 0.0_dp
    2305             : 
    2306             :       !Strategy: most terms are either multiplied by drhoa or drhob => group those first and then
    2307             :       !          multiply. Also most terms are multiplied by the dot product grad_n . grad_so, so
    2308             :       !          precompute it as well
    2309             : 
    2310             : !$OMP PARALLEL DEFAULT(NONE), &
    2311             : !$OMP SHARED(dot_proda,dot_prodb,tmp,vxc,vxg,deriv_set,rho_set,na,nr,norm_drhoa,norm_drhob,dso, &
    2312             : !$OMP        so,weight,ub), &
    2313        2006 : !$OMP PRIVATE(ia,ir,dir,deriv,d1e,d2e)
    2314             : 
    2315             :       !Precompute the very common dot products grad_na . grad_so and grad_nb . grad_so
    2316             :       DO dir = 1, 3
    2317             : !$OMP DO SCHEDULE(STATIC) COLLAPSE(2)
    2318             :          DO ir = 1, nr
    2319             :             DO ia = 1, na
    2320             :                dot_proda(ia, ir) = dot_proda(ia, ir) + rho_set%drhoa(dir)%array(ia, ir, 1)*dso(ia, ir, dir)
    2321             :                dot_prodb(ia, ir) = dot_prodb(ia, ir) + rho_set%drhob(dir)%array(ia, ir, 1)*dso(ia, ir, dir)
    2322             :             END DO !ia
    2323             :          END DO !ir
    2324             : !$OMP END DO NOWAIT
    2325             :       END DO !dir
    2326             : 
    2327             :       !Deal with f_aa
    2328             : 
    2329             :       !Vxc, first term
    2330             :       deriv => xc_dset_get_derivative(deriv_set, [deriv_rhoa, deriv_norm_drhoa])
    2331             :       IF (ASSOCIATED(deriv)) THEN
    2332             :          CALL xc_derivative_get(deriv, deriv_data=d2e)
    2333             : !$OMP DO SCHEDULE(STATIC) COLLAPSE(2)
    2334             :          DO ir = 1, nr
    2335             :             DO ia = 1, na
    2336             :                vxc(1)%array(ia, ir) = d2e(ia, ir, 1)*dot_proda(ia, ir)
    2337             :             END DO !ia
    2338             :          END DO !ir
    2339             : !$OMP END DO NOWAIT
    2340             :       END IF
    2341             : 
    2342             :       !Vxc, second term
    2343             :       deriv => xc_dset_get_derivative(deriv_set, [deriv_rhoa, deriv_norm_drho])
    2344             : 
    2345             :       IF (ASSOCIATED(deriv)) THEN
    2346             :          CALL xc_derivative_get(deriv, deriv_data=d2e)
    2347             : !$OMP DO SCHEDULE(STATIC) COLLAPSE(2)
    2348             :          DO ir = 1, nr
    2349             :             DO ia = 1, na
    2350             :                vxc(1)%array(ia, ir) = vxc(1)%array(ia, ir) + d2e(ia, ir, 1)*dot_prodb(ia, ir)
    2351             :             END DO !ia
    2352             :          END DO !ir
    2353             : !$OMP END DO NOWAIT
    2354             :       END IF
    2355             : 
    2356             :       !Vxc, take the grid weight into acocunt
    2357             : !$OMP DO SCHEDULE(STATIC) COLLAPSE(2)
    2358             :       DO ir = 1, nr
    2359             :          DO ia = 1, na
    2360             :             vxc(1)%array(ia, ir) = vxc(1)%array(ia, ir)*weight(ia, ir)
    2361             :          END DO !ia
    2362             :       END DO !ir
    2363             : !$OMP END DO NOWAIT
    2364             : 
    2365             :       !Vxg, first term (to be multiplied by drhoa)
    2366             :       deriv => xc_dset_get_derivative(deriv_set, [deriv_rhoa, deriv_norm_drhoa])
    2367             :       IF (ASSOCIATED(deriv)) THEN
    2368             :          CALL xc_derivative_get(deriv, deriv_data=d2e)
    2369             : !$OMP DO SCHEDULE(STATIC) COLLAPSE(2)
    2370             :          DO ir = 1, nr
    2371             :             DO ia = 1, na
    2372             :                tmp(ia, ir) = d2e(ia, ir, 1)*so(ia, ir)
    2373             :             END DO !ia
    2374             :          END DO !ir
    2375             : !$OMP END DO NOWAIT
    2376             :       END IF
    2377             : 
    2378             :       !Vxg, second term (to be multiplied by drhoa)
    2379             :       deriv => xc_dset_get_derivative(deriv_set, [deriv_norm_drhoa, deriv_norm_drho])
    2380             :       IF (ASSOCIATED(deriv)) THEN
    2381             :          CALL xc_derivative_get(deriv, deriv_data=d2e)
    2382             : !$OMP DO SCHEDULE(STATIC) COLLAPSE(2)
    2383             :          DO ir = 1, nr
    2384             :             DO ia = 1, na
    2385             :                tmp(ia, ir) = tmp(ia, ir) + d2e(ia, ir, 1)*dot_prodb(ia, ir)
    2386             :             END DO !ia
    2387             :          END DO !ir
    2388             : !$OMP END DO NOWAIT
    2389             :       END IF
    2390             : 
    2391             :       !Vxg, third term (to be multiplied by drhoa)
    2392             :       deriv => xc_dset_get_derivative(deriv_set, [deriv_norm_drhoa, deriv_norm_drhoa])
    2393             :       IF (ASSOCIATED(deriv)) THEN
    2394             :          CALL xc_derivative_get(deriv, deriv_data=d2e)
    2395             : !$OMP DO SCHEDULE(STATIC) COLLAPSE(2)
    2396             :          DO ir = 1, nr
    2397             :             DO ia = 1, na
    2398             :                tmp(ia, ir) = tmp(ia, ir) + d2e(ia, ir, 1)*dot_proda(ia, ir)
    2399             :             END DO !ia
    2400             :          END DO !ir
    2401             : !$OMP END DO NOWAIT
    2402             :       END IF
    2403             : 
    2404             :       !Vxg, fourth term (to be multiplied by drhoa)
    2405             :       deriv => xc_dset_get_derivative(deriv_set, [deriv_norm_drhoa])
    2406             :       IF (ASSOCIATED(deriv)) THEN
    2407             :          CALL xc_derivative_get(deriv, deriv_data=d1e)
    2408             : !$OMP DO SCHEDULE(STATIC) COLLAPSE(2)
    2409             :          DO ir = 1, nr
    2410             :             DO ia = 1, na
    2411             :                tmp(ia, ir) = tmp(ia, ir) - d1e(ia, ir, 1)*dot_proda(ia, ir) &
    2412             :                              /MAX(norm_drhoa(ia, ir, 1), rho_set%drho_cutoff)**2
    2413             :             END DO !ia
    2414             :          END DO !ir
    2415             : !$OMP END DO NOWAIT
    2416             :       END IF
    2417             : 
    2418             :       !put tmp*drhoa in Vxg (so that we can reuse it for drhob terms)
    2419             :       DO dir = 1, 3
    2420             : !$OMP DO SCHEDULE(STATIC) COLLAPSE(2)
    2421             :          DO ir = 1, nr
    2422             :             DO ia = 1, na
    2423             :                vxg(1)%array(ia, ir, dir) = tmp(ia, ir)*rho_set%drhoa(dir)%array(ia, ir, 1)
    2424             :             END DO !ia
    2425             :          END DO !ir
    2426             : !$OMP END DO NOWAIT
    2427             :       END DO !dir
    2428             : 
    2429             :       !Vxg, fifth term (to be multiplied by drhob)
    2430             :       deriv => xc_dset_get_derivative(deriv_set, [deriv_rhoa, deriv_norm_drho])
    2431             :       IF (ASSOCIATED(deriv)) THEN
    2432             :          CALL xc_derivative_get(deriv, deriv_data=d2e)
    2433             : !$OMP DO SCHEDULE(STATIC) COLLAPSE(2)
    2434             :          DO ir = 1, nr
    2435             :             DO ia = 1, na
    2436             :                tmp(ia, ir) = d2e(ia, ir, 1)*so(ia, ir)
    2437             :             END DO !ia
    2438             :          END DO !ir
    2439             : !$OMP END DO NOWAIT
    2440             :       END IF
    2441             : 
    2442             :       !Vxg, sixth term (to be multiplied by drhob)
    2443             :       deriv => xc_dset_get_derivative(deriv_set, [deriv_norm_drhoa, deriv_norm_drho])
    2444             :       IF (ASSOCIATED(deriv)) THEN
    2445             :          CALL xc_derivative_get(deriv, deriv_data=d2e)
    2446             : !$OMP DO SCHEDULE(STATIC) COLLAPSE(2)
    2447             :          DO ir = 1, nr
    2448             :             DO ia = 1, na
    2449             :                tmp(ia, ir) = tmp(ia, ir) + d2e(ia, ir, 1)*dot_proda(ia, ir)
    2450             :             END DO !ia
    2451             :          END DO !ir
    2452             : !$OMP END DO NOWAIT
    2453             :       END IF
    2454             : 
    2455             :       !Vxg, seventh term (to be multiplied by drhob)
    2456             :       deriv => xc_dset_get_derivative(deriv_set, [deriv_norm_drho, deriv_norm_drho])
    2457             :       IF (ASSOCIATED(deriv)) THEN
    2458             :          CALL xc_derivative_get(deriv, deriv_data=d2e)
    2459             : !$OMP DO SCHEDULE(STATIC) COLLAPSE(2)
    2460             :          DO ir = 1, nr
    2461             :             DO ia = 1, na
    2462             :                tmp(ia, ir) = tmp(ia, ir) + d2e(ia, ir, 1)*dot_prodb(ia, ir)
    2463             :             END DO !ia
    2464             :          END DO !ir
    2465             : !$OMP END DO NOWAIT
    2466             :       END IF
    2467             : 
    2468             :       !put tmp*drhob in Vxg
    2469             :       DO dir = 1, 3
    2470             : !$OMP DO SCHEDULE(STATIC) COLLAPSE(2)
    2471             :          DO ir = 1, nr
    2472             :             DO ia = 1, na
    2473             :                vxg(1)%array(ia, ir, dir) = vxg(1)%array(ia, ir, dir) + tmp(ia, ir)*rho_set%drhob(dir)%array(ia, ir, 1)
    2474             :             END DO !ia
    2475             :          END DO !ir
    2476             : !$OMP END DO NOWAIT
    2477             :       END DO !dir
    2478             : 
    2479             :       !Vxg, last term
    2480             :       deriv => xc_dset_get_derivative(deriv_set, [deriv_norm_drhoa])
    2481             :       IF (ASSOCIATED(deriv)) THEN
    2482             :          CALL xc_derivative_get(deriv, deriv_data=d1e)
    2483             :          DO dir = 1, 3
    2484             : !$OMP DO SCHEDULE(STATIC) COLLAPSE(2)
    2485             :             DO ir = 1, nr
    2486             :                DO ia = 1, na
    2487             :                   vxg(1)%array(ia, ir, dir) = vxg(1)%array(ia, ir, dir) + d1e(ia, ir, 1)*dso(ia, ir, dir)
    2488             :                END DO !ia
    2489             :             END DO !ir
    2490             : !$OMP END DO NOWAIT
    2491             :          END DO !dir
    2492             :       END IF
    2493             : 
    2494             :       !Vxg, take the grid weight into account
    2495             :       DO dir = 1, 3
    2496             : !$OMP DO SCHEDULE(STATIC) COLLAPSE(2)
    2497             :          DO ir = 1, nr
    2498             :             DO ia = 1, na
    2499             :                vxg(1)%array(ia, ir, dir) = vxg(1)%array(ia, ir, dir)*weight(ia, ir)
    2500             :             END DO !ia
    2501             :          END DO !ir
    2502             : !$OMP END DO NOWAIT
    2503             :       END DO !dir
    2504             : 
    2505             :       !Deal with fab
    2506             : 
    2507             :       !Vxc, first term
    2508             :       deriv => xc_dset_get_derivative(deriv_set, [deriv_rhoa, deriv_norm_drhob])
    2509             :       IF (ASSOCIATED(deriv)) THEN
    2510             :          CALL xc_derivative_get(deriv, deriv_data=d2e)
    2511             : !$OMP DO SCHEDULE(STATIC) COLLAPSE(2)
    2512             :          DO ir = 1, nr
    2513             :             DO ia = 1, na
    2514             :                vxc(2)%array(ia, ir) = d2e(ia, ir, 1)*dot_prodb(ia, ir)
    2515             :             END DO !ia
    2516             :          END DO !ir
    2517             : !$OMP END DO NOWAIT
    2518             :       END IF
    2519             : 
    2520             :       !Vxc, second term
    2521             :       deriv => xc_dset_get_derivative(deriv_set, [deriv_rhoa, deriv_norm_drho])
    2522             :       IF (ASSOCIATED(deriv)) THEN
    2523             :          CALL xc_derivative_get(deriv, deriv_data=d2e)
    2524             : !$OMP DO SCHEDULE(STATIC) COLLAPSE(2)
    2525             :          DO ir = 1, nr
    2526             :             DO ia = 1, na
    2527             :                vxc(2)%array(ia, ir) = vxc(2)%array(ia, ir) + d2e(ia, ir, 1)*dot_proda(ia, ir)
    2528             :             END DO !ia
    2529             :          END DO !ir
    2530             : !$OMP END DO NOWAIT
    2531             :       END IF
    2532             : 
    2533             :       !Vxc, take the grid weight into acocunt
    2534             : !$OMP DO SCHEDULE(STATIC) COLLAPSE(2)
    2535             :       DO ir = 1, nr
    2536             :          DO ia = 1, na
    2537             :             vxc(2)%array(ia, ir) = vxc(2)%array(ia, ir)*weight(ia, ir)
    2538             :          END DO !ia
    2539             :       END DO !ir
    2540             : !$OMP END DO NOWAIT
    2541             : 
    2542             :       !Vxg, first term (to be multiplied by drhoa)
    2543             :       deriv => xc_dset_get_derivative(deriv_set, [deriv_rhob, deriv_norm_drhoa])
    2544             :       IF (ASSOCIATED(deriv)) THEN
    2545             :          CALL xc_derivative_get(deriv, deriv_data=d2e)
    2546             : !$OMP DO SCHEDULE(STATIC) COLLAPSE(2)
    2547             :          DO ir = 1, nr
    2548             :             DO ia = 1, na
    2549             :                tmp(ia, ir) = d2e(ia, ir, 1)*so(ia, ir)
    2550             :             END DO !ia
    2551             :          END DO !ir
    2552             : !$OMP END DO NOWAIT
    2553             :       END IF
    2554             : 
    2555             :       !Vxg, second term (to be multiplied by drhoa)
    2556             :       deriv => xc_dset_get_derivative(deriv_set, [deriv_norm_drhoa, deriv_norm_drho])
    2557             :       IF (ASSOCIATED(deriv)) THEN
    2558             :          CALL xc_derivative_get(deriv, deriv_data=d2e)
    2559             : !$OMP DO SCHEDULE(STATIC) COLLAPSE(2)
    2560             :          DO ir = 1, nr
    2561             :             DO ia = 1, na
    2562             :                tmp(ia, ir) = tmp(ia, ir) + d2e(ia, ir, 1)*dot_proda(ia, ir)
    2563             :             END DO !ia
    2564             :          END DO !ir
    2565             : !$OMP END DO NOWAIT
    2566             :       END IF
    2567             : 
    2568             :       !Vxg, third term (to be multiplied by drhoa)
    2569             :       deriv => xc_dset_get_derivative(deriv_set, [deriv_norm_drhoa, deriv_norm_drhob])
    2570             :       IF (ASSOCIATED(deriv)) THEN
    2571             :          CALL xc_derivative_get(deriv, deriv_data=d2e)
    2572             : !$OMP DO SCHEDULE(STATIC) COLLAPSE(2)
    2573             :          DO ir = 1, nr
    2574             :             DO ia = 1, na
    2575             :                tmp(ia, ir) = tmp(ia, ir) + d2e(ia, ir, 1)*dot_prodb(ia, ir)
    2576             :             END DO !ia
    2577             :          END DO !ir
    2578             : !$OMP END DO NOWAIT
    2579             :       END IF
    2580             : 
    2581             :       !put tmp*drhoa in Vxg
    2582             :       DO dir = 1, 3
    2583             : !$OMP DO SCHEDULE(STATIC) COLLAPSE(2)
    2584             :          DO ir = 1, nr
    2585             :             DO ia = 1, na
    2586             :                vxg(2)%array(ia, ir, dir) = tmp(ia, ir)*rho_set%drhoa(dir)%array(ia, ir, 1)
    2587             :             END DO !ia
    2588             :          END DO !ir
    2589             : !$OMP END DO NOWAIT
    2590             :       END DO !dir
    2591             : 
    2592             :       !Vxg, fourth term (to be multiplied by drhob)
    2593             :       deriv => xc_dset_get_derivative(deriv_set, [deriv_rhob, deriv_norm_drho])
    2594             :       IF (ASSOCIATED(deriv)) THEN
    2595             :          CALL xc_derivative_get(deriv, deriv_data=d2e)
    2596             : !$OMP DO SCHEDULE(STATIC) COLLAPSE(2)
    2597             :          DO ir = 1, nr
    2598             :             DO ia = 1, na
    2599             :                tmp(ia, ir) = d2e(ia, ir, 1)*so(ia, ir)
    2600             :             END DO !ia
    2601             :          END DO !ir
    2602             : !$OMP END DO NOWAIT
    2603             :       END IF
    2604             : 
    2605             :       !Vxg, fifth term (to be multiplied by drhob)
    2606             :       deriv => xc_dset_get_derivative(deriv_set, [deriv_norm_drho, deriv_norm_drhob])
    2607             :       IF (ASSOCIATED(deriv)) THEN
    2608             :          CALL xc_derivative_get(deriv, deriv_data=d2e)
    2609             : !$OMP DO SCHEDULE(STATIC) COLLAPSE(2)
    2610             :          DO ir = 1, nr
    2611             :             DO ia = 1, na
    2612             :                tmp(ia, ir) = tmp(ia, ir) + d2e(ia, ir, 1)*dot_prodb(ia, ir)
    2613             :             END DO !ia
    2614             :          END DO !ir
    2615             : !$OMP END DO NOWAIT
    2616             :       END IF
    2617             : 
    2618             :       !Vxg, sixth term (to be multiplied by drhob)
    2619             :       deriv => xc_dset_get_derivative(deriv_set, [deriv_norm_drho, deriv_norm_drho])
    2620             :       IF (ASSOCIATED(deriv)) THEN
    2621             :          CALL xc_derivative_get(deriv, deriv_data=d2e)
    2622             : !$OMP DO SCHEDULE(STATIC) COLLAPSE(2)
    2623             :          DO ir = 1, nr
    2624             :             DO ia = 1, na
    2625             :                tmp(ia, ir) = tmp(ia, ir) + d2e(ia, ir, 1)*dot_proda(ia, ir)
    2626             :             END DO !ia
    2627             :          END DO !ir
    2628             : !$OMP END DO NOWAIT
    2629             :       END IF
    2630             : 
    2631             :       !put tmp*drhob in Vxg
    2632             :       DO dir = 1, 3
    2633             : !$OMP DO SCHEDULE(STATIC) COLLAPSE(2)
    2634             :          DO ir = 1, nr
    2635             :             DO ia = 1, na
    2636             :                vxg(2)%array(ia, ir, dir) = vxg(2)%array(ia, ir, dir) + tmp(ia, ir)*rho_set%drhob(dir)%array(ia, ir, 1)
    2637             :             END DO
    2638             :          END DO
    2639             : !$OMP END DO NOWAIT
    2640             :       END DO
    2641             : 
    2642             :       !Vxg, last term
    2643             :       deriv => xc_dset_get_derivative(deriv_set, [deriv_norm_drho])
    2644             :       IF (ASSOCIATED(deriv)) THEN
    2645             :          CALL xc_derivative_get(deriv, deriv_data=d1e)
    2646             :          DO dir = 1, 3
    2647             : !$OMP DO SCHEDULE(STATIC) COLLAPSE(2)
    2648             :             DO ir = 1, nr
    2649             :                DO ia = 1, na
    2650             :                   vxg(2)%array(ia, ir, dir) = vxg(2)%array(ia, ir, dir) + d1e(ia, ir, 1)*dso(ia, ir, dir)
    2651             :                END DO !ia
    2652             :             END DO !ir
    2653             : !$OMP END DO NOWAIT
    2654             :          END DO !dir
    2655             :       END IF
    2656             : 
    2657             :       !Vxg, take the grid weight into account
    2658             :       DO dir = 1, 3
    2659             : !$OMP DO SCHEDULE(STATIC) COLLAPSE(2)
    2660             :          DO ir = 1, nr
    2661             :             DO ia = 1, na
    2662             :                vxg(2)%array(ia, ir, dir) = vxg(2)%array(ia, ir, dir)*weight(ia, ir)
    2663             :             END DO !ia
    2664             :          END DO !ir
    2665             : !$OMP END DO NOWAIT
    2666             :       END DO !dir
    2667             : 
    2668             :       !Deal with f_bb, if so required
    2669             :       IF (ub == 3) THEN
    2670             : 
    2671             :          !Vxc, first term
    2672             :          deriv => xc_dset_get_derivative(deriv_set, [deriv_rhob, deriv_norm_drhob])
    2673             :          IF (ASSOCIATED(deriv)) THEN
    2674             :             CALL xc_derivative_get(deriv, deriv_data=d2e)
    2675             : !$OMP DO SCHEDULE(STATIC) COLLAPSE(2)
    2676             :             DO ir = 1, nr
    2677             :                DO ia = 1, na
    2678             :                   vxc(3)%array(ia, ir) = d2e(ia, ir, 1)*dot_prodb(ia, ir)
    2679             :                END DO !ia
    2680             :             END DO !ir
    2681             : !$OMP END DO NOWAIT
    2682             :          END IF
    2683             : 
    2684             :          !Vxc, second term
    2685             :          deriv => xc_dset_get_derivative(deriv_set, [deriv_rhob, deriv_norm_drho])
    2686             :          IF (ASSOCIATED(deriv)) THEN
    2687             :             CALL xc_derivative_get(deriv, deriv_data=d2e)
    2688             : !$OMP DO SCHEDULE(STATIC) COLLAPSE(2)
    2689             :             DO ir = 1, nr
    2690             :                DO ia = 1, na
    2691             :                   vxc(3)%array(ia, ir) = vxc(3)%array(ia, ir) + d2e(ia, ir, 1)*dot_proda(ia, ir)
    2692             :                END DO !i
    2693             :             END DO !ir
    2694             : !$OMP END DO NOWAIT
    2695             :          END IF
    2696             : 
    2697             :          !Vxc, take the grid weight into acocunt
    2698             : !$OMP DO SCHEDULE(STATIC) COLLAPSE(2)
    2699             :          DO ir = 1, nr
    2700             :             DO ia = 1, na
    2701             :                vxc(3)%array(ia, ir) = vxc(3)%array(ia, ir)*weight(ia, ir)
    2702             :             END DO !ia
    2703             :          END DO !ir
    2704             : !$OMP END DO NOWAIT
    2705             : 
    2706             :          !Vxg, first term (to be multiplied by drhob)
    2707             :          deriv => xc_dset_get_derivative(deriv_set, [deriv_rhob, deriv_norm_drhob])
    2708             :          IF (ASSOCIATED(deriv)) THEN
    2709             :             CALL xc_derivative_get(deriv, deriv_data=d2e)
    2710             : !$OMP DO SCHEDULE(STATIC) COLLAPSE(2)
    2711             :             DO ir = 1, nr
    2712             :                DO ia = 1, na
    2713             :                   tmp(ia, ir) = d2e(ia, ir, 1)*so(ia, ir)
    2714             :                END DO !ia
    2715             :             END DO !ir
    2716             : !$OMP END DO NOWAIT
    2717             :          END IF
    2718             : 
    2719             :          !Vxg, second term (to be multiplied by drhob)
    2720             :          deriv => xc_dset_get_derivative(deriv_set, [deriv_norm_drhob, deriv_norm_drho])
    2721             :          IF (ASSOCIATED(deriv)) THEN
    2722             :             CALL xc_derivative_get(deriv, deriv_data=d2e)
    2723             : !$OMP DO SCHEDULE(STATIC) COLLAPSE(2)
    2724             :             DO ir = 1, nr
    2725             :                DO ia = 1, na
    2726             :                   tmp(ia, ir) = tmp(ia, ir) + d2e(ia, ir, 1)*dot_proda(ia, ir)
    2727             :                END DO !ia
    2728             :             END DO !ir
    2729             : !$OMP END DO NOWAIT
    2730             :          END IF
    2731             : 
    2732             :          !Vxg, third term (to be multiplied by drhob)
    2733             :          deriv => xc_dset_get_derivative(deriv_set, [deriv_norm_drhob, deriv_norm_drhob])
    2734             :          IF (ASSOCIATED(deriv)) THEN
    2735             :             CALL xc_derivative_get(deriv, deriv_data=d2e)
    2736             : !$OMP DO SCHEDULE(STATIC) COLLAPSE(2)
    2737             :             DO ir = 1, nr
    2738             :                DO ia = 1, na
    2739             :                   tmp(ia, ir) = tmp(ia, ir) + d2e(ia, ir, 1)*dot_prodb(ia, ir)
    2740             :                END DO !ia
    2741             :             END DO !ir
    2742             : !$OMP END DO NOWAIT
    2743             :          END IF
    2744             : 
    2745             :          !Vxg, fourth term (to be multiplied by drhob)
    2746             :          deriv => xc_dset_get_derivative(deriv_set, [deriv_norm_drhob])
    2747             :          IF (ASSOCIATED(deriv)) THEN
    2748             :             CALL xc_derivative_get(deriv, deriv_data=d1e)
    2749             : !$OMP DO SCHEDULE(STATIC) COLLAPSE(2)
    2750             :             DO ir = 1, nr
    2751             :                DO ia = 1, na
    2752             :                   tmp(ia, ir) = tmp(ia, ir) - d1e(ia, ir, 1)*dot_prodb(ia, ir) &
    2753             :                                 /MAX(norm_drhob(ia, ir, 1), rho_set%drho_cutoff)**2
    2754             :                END DO !ia
    2755             :             END DO !ir
    2756             : !$OMP END DO NOWAIT
    2757             :          END IF
    2758             : 
    2759             :          !put tmp*drhob in Vxg (so that we can reuse it for drhoa terms)
    2760             :          DO dir = 1, 3
    2761             : !$OMP DO SCHEDULE(STATIC) COLLAPSE(2)
    2762             :             DO ir = 1, nr
    2763             :                DO ia = 1, na
    2764             :                   vxg(3)%array(ia, ir, dir) = tmp(ia, ir)*rho_set%drhob(dir)%array(ia, ir, 1)
    2765             :                END DO !ia
    2766             :             END DO !ir
    2767             : !$OMP END DO NOWAIT
    2768             :          END DO !dir
    2769             : 
    2770             :          !Vxg, fifth term (to be multiplied by drhoa)
    2771             :          deriv => xc_dset_get_derivative(deriv_set, [deriv_rhob, deriv_norm_drho])
    2772             :          IF (ASSOCIATED(deriv)) THEN
    2773             :             CALL xc_derivative_get(deriv, deriv_data=d2e)
    2774             : !$OMP DO SCHEDULE(STATIC) COLLAPSE(2)
    2775             :             DO ir = 1, nr
    2776             :                DO ia = 1, na
    2777             :                   tmp(ia, ir) = d2e(ia, ir, 1)*so(ia, ir)
    2778             :                END DO !ia
    2779             :             END DO !ir
    2780             : !$OMP END DO NOWAIT
    2781             :          END IF
    2782             : 
    2783             :          !Vxg, sixth term (to be multiplied by drhoa)
    2784             :          deriv => xc_dset_get_derivative(deriv_set, [deriv_norm_drhob, deriv_norm_drho])
    2785             :          IF (ASSOCIATED(deriv)) THEN
    2786             :             CALL xc_derivative_get(deriv, deriv_data=d2e)
    2787             : !$OMP DO SCHEDULE(STATIC) COLLAPSE(2)
    2788             :             DO ir = 1, nr
    2789             :                DO ia = 1, na
    2790             :                   tmp(ia, ir) = tmp(ia, ir) + d2e(ia, ir, 1)*dot_prodb(ia, ir)
    2791             :                END DO !ia
    2792             :             END DO !ir
    2793             : !$OMP END DO NOWAIT
    2794             :          END IF
    2795             : 
    2796             :          !Vxg, seventh term (to be multiplied by drhoa)
    2797             :          deriv => xc_dset_get_derivative(deriv_set, [deriv_norm_drho, deriv_norm_drho])
    2798             :          IF (ASSOCIATED(deriv)) THEN
    2799             :             CALL xc_derivative_get(deriv, deriv_data=d2e)
    2800             : !$OMP DO SCHEDULE(STATIC) COLLAPSE(2)
    2801             :             DO ir = 1, nr
    2802             :                DO ia = 1, na
    2803             :                   tmp(ia, ir) = tmp(ia, ir) + d2e(ia, ir, 1)*dot_proda(ia, ir)
    2804             :                END DO !ia
    2805             :             END DO !ir
    2806             : !$OMP END DO NOWAIT
    2807             :          END IF
    2808             : 
    2809             :          !put tmp*drhoa in Vxg
    2810             :          DO dir = 1, 3
    2811             : !$OMP DO SCHEDULE(STATIC) COLLAPSE(2)
    2812             :             DO ir = 1, nr
    2813             :                DO ia = 1, na
    2814             :                   vxg(3)%array(ia, ir, dir) = vxg(3)%array(ia, ir, dir) + &
    2815             :                                               tmp(ia, ir)*rho_set%drhoa(dir)%array(ia, ir, 1)
    2816             :                END DO !ia
    2817             :             END DO !ir
    2818             : !$OMP END DO NOWAIT
    2819             :          END DO !dir
    2820             : 
    2821             :          !Vxg, last term
    2822             :          deriv => xc_dset_get_derivative(deriv_set, [deriv_norm_drhob])
    2823             :          IF (ASSOCIATED(deriv)) THEN
    2824             :             CALL xc_derivative_get(deriv, deriv_data=d1e)
    2825             :             DO dir = 1, 3
    2826             : !$OMP DO SCHEDULE(STATIC) COLLAPSE(2)
    2827             :                DO ir = 1, nr
    2828             :                   DO ia = 1, na
    2829             :                      vxg(3)%array(ia, ir, dir) = vxg(3)%array(ia, ir, dir) + d1e(ia, ir, 1)*dso(ia, ir, dir)
    2830             :                   END DO !ia
    2831             :                END DO !ir
    2832             : !$OMP END DO NOWAIT
    2833             :             END DO !dir
    2834             :          END IF
    2835             : 
    2836             :          !Vxg, take the grid weight into account
    2837             :          DO dir = 1, 3
    2838             : !$OMP DO SCHEDULE(STATIC) COLLAPSE(2)
    2839             :             DO ir = 1, nr
    2840             :                DO ia = 1, na
    2841             :                   vxg(3)%array(ia, ir, dir) = vxg(3)%array(ia, ir, dir)*weight(ia, ir)
    2842             :                END DO !ia
    2843             :             END DO !ir
    2844             : !$OMP END DO NOWAIT
    2845             :          END DO !dir
    2846             : 
    2847             :       END IF !f_bb
    2848             : 
    2849             : !$OMP END PARALLEL
    2850             : 
    2851        2006 :       CALL timestop(handle)
    2852             : 
    2853        4012 :    END SUBROUTINE get_vxc_vxg
    2854             : 
    2855             : ! **************************************************************************************************
    2856             : !> \brief Integrate the fxc kernel in the spin-conserving case, be it closed- or open-shell
    2857             : !> \param int_fxc the array containing the (P|fxc|Q) integrals
    2858             : !> \param iatom the index of the current excited atom
    2859             : !> \param ikind the index of the current excited kind
    2860             : !> \param deriv_set the set of functional derivatives
    2861             : !> \param xas_atom_env ...
    2862             : !> \param qs_env ...
    2863             : ! **************************************************************************************************
    2864          38 :    SUBROUTINE integrate_sc_fxc(int_fxc, iatom, ikind, deriv_set, xas_atom_env, qs_env)
    2865             : 
    2866             :       TYPE(cp_2d_r_p_type), DIMENSION(:, :), POINTER     :: int_fxc
    2867             :       INTEGER, INTENT(IN)                                :: iatom, ikind
    2868             :       TYPE(xc_derivative_set_type), INTENT(IN)           :: deriv_set
    2869             :       TYPE(xas_atom_env_type), POINTER                   :: xas_atom_env
    2870             :       TYPE(qs_environment_type), POINTER                 :: qs_env
    2871             : 
    2872             :       INTEGER                                            :: i, maxso, na, nr, nset, nsotot, nspins, &
    2873             :                                                             ri_nsgf, ub
    2874             :       REAL(dp), ALLOCATABLE, DIMENSION(:, :)             :: fxc, int_so
    2875             :       REAL(dp), DIMENSION(:, :), POINTER                 :: ri_sphi_so
    2876          38 :       TYPE(cp_3d_r_p_type), ALLOCATABLE, DIMENSION(:)    :: d2e
    2877             :       TYPE(dft_control_type), POINTER                    :: dft_control
    2878             :       TYPE(grid_atom_type), POINTER                      :: grid_atom
    2879             :       TYPE(gto_basis_set_type), POINTER                  :: ri_basis
    2880          38 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
    2881             :       TYPE(xc_derivative_type), POINTER                  :: deriv
    2882             : 
    2883          38 :       NULLIFY (grid_atom, deriv, ri_basis, ri_sphi_so, qs_kind_set, dft_control)
    2884             : 
    2885             :       ! Initialization
    2886          38 :       CALL get_qs_env(qs_env, qs_kind_set=qs_kind_set, dft_control=dft_control)
    2887          38 :       grid_atom => xas_atom_env%grid_atom_set(ikind)%grid_atom
    2888          38 :       na = grid_atom%ng_sphere
    2889          38 :       nr = grid_atom%nr
    2890          38 :       CALL get_qs_kind(qs_kind_set(ikind), basis_set=ri_basis, basis_type="RI_XAS")
    2891          38 :       CALL get_gto_basis_set(ri_basis, nset=nset, maxso=maxso, nsgf=ri_nsgf)
    2892          38 :       nsotot = nset*maxso
    2893          38 :       ri_sphi_so => xas_atom_env%ri_sphi_so(ikind)%array
    2894          38 :       nspins = dft_control%nspins
    2895             : 
    2896             :       ! Get the second derivatives
    2897         190 :       ALLOCATE (d2e(3))
    2898          38 :       deriv => xc_dset_get_derivative(deriv_set, [deriv_rhoa, deriv_rhoa])
    2899          38 :       CALL xc_derivative_get(deriv, deriv_data=d2e(1)%array)
    2900          38 :       deriv => xc_dset_get_derivative(deriv_set, [deriv_rhoa, deriv_rhob])
    2901          38 :       CALL xc_derivative_get(deriv, deriv_data=d2e(2)%array)
    2902          38 :       deriv => xc_dset_get_derivative(deriv_set, [deriv_rhob, deriv_rhob])
    2903          38 :       CALL xc_derivative_get(deriv, deriv_data=d2e(3)%array)
    2904             : 
    2905             :       ! Allocate some work arrays
    2906         152 :       ALLOCATE (fxc(na, nr))
    2907         152 :       ALLOCATE (int_so(nsotot, nsotot))
    2908             : 
    2909             :       ! Integrate for all three derivatives, taking the grid weight into account
    2910             :       ! If closed shell, do not need to integrate beta-beta as it is the same as alpha-alpha
    2911          38 :       ub = 2; IF (nspins == 2) ub = 3
    2912         116 :       DO i = 1, ub
    2913             : 
    2914     4393650 :          int_so = 0.0_dp
    2915     2058330 :          fxc(:, :) = d2e(i)%array(:, :, 1)*grid_atom%weight(:, :)
    2916          78 :          CALL integrate_so_prod(int_so, fxc, ikind, xas_atom_env, qs_env)
    2917             : 
    2918             :          !contract into sgf. Array allocated on current processor only
    2919         312 :          ALLOCATE (int_fxc(iatom, i)%array(ri_nsgf, ri_nsgf))
    2920      506066 :          int_fxc(iatom, i)%array = 0.0_dp
    2921         116 :          CALL contract_so2sgf(int_fxc(iatom, i)%array, int_so, ri_basis, ri_sphi_so)
    2922             : 
    2923             :       END DO
    2924             : 
    2925         114 :    END SUBROUTINE integrate_sc_fxc
    2926             : 
    2927             : ! **************************************************************************************************
    2928             : !> \brief Integrate the fxc kernel in the spin-flip case (open-shell assumed). The spin-flip LDA
    2929             : !>        kernel reads: fxc = 1/(rhoa - rhob) * (dE/drhoa - dE/drhob)
    2930             : !> \param int_fxc the array containing the (P|fxc|Q) integrals
    2931             : !> \param iatom the index of the current excited atom
    2932             : !> \param ikind the index of the current excited kind
    2933             : !> \param rho_set the density in the atomic grid
    2934             : !> \param deriv_set the set of functional derivatives
    2935             : !> \param xas_atom_env ...
    2936             : !> \param qs_env ...
    2937             : ! **************************************************************************************************
    2938           0 :    SUBROUTINE integrate_sf_fxc(int_fxc, iatom, ikind, rho_set, deriv_set, xas_atom_env, qs_env)
    2939             : 
    2940             :       TYPE(cp_2d_r_p_type), DIMENSION(:, :), POINTER     :: int_fxc
    2941             :       INTEGER, INTENT(IN)                                :: iatom, ikind
    2942             :       TYPE(xc_rho_set_type), INTENT(IN)                  :: rho_set
    2943             :       TYPE(xc_derivative_set_type), INTENT(IN)           :: deriv_set
    2944             :       TYPE(xas_atom_env_type), POINTER                   :: xas_atom_env
    2945             :       TYPE(qs_environment_type), POINTER                 :: qs_env
    2946             : 
    2947             :       INTEGER                                            :: ia, ir, maxso, na, nr, nset, nsotot, &
    2948             :                                                             ri_nsgf
    2949           0 :       REAL(dp), ALLOCATABLE, DIMENSION(:, :)             :: fxc, int_so
    2950             :       REAL(dp), DIMENSION(:, :), POINTER                 :: ri_sphi_so
    2951           0 :       REAL(dp), DIMENSION(:, :, :), POINTER              :: rhoa, rhob
    2952           0 :       TYPE(cp_3d_r_p_type), ALLOCATABLE, DIMENSION(:)    :: d1e, d2e
    2953             :       TYPE(dft_control_type), POINTER                    :: dft_control
    2954             :       TYPE(grid_atom_type), POINTER                      :: grid_atom
    2955             :       TYPE(gto_basis_set_type), POINTER                  :: ri_basis
    2956           0 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
    2957             :       TYPE(xc_derivative_type), POINTER                  :: deriv
    2958             : 
    2959           0 :       NULLIFY (grid_atom, deriv, ri_basis, ri_sphi_so, qs_kind_set, rhoa, rhob, dft_control)
    2960             : 
    2961             :       ! Initialization
    2962           0 :       CALL get_qs_env(qs_env, qs_kind_set=qs_kind_set, dft_control=dft_control)
    2963           0 :       grid_atom => xas_atom_env%grid_atom_set(ikind)%grid_atom
    2964           0 :       na = grid_atom%ng_sphere
    2965           0 :       nr = grid_atom%nr
    2966           0 :       CALL get_qs_kind(qs_kind_set(ikind), basis_set=ri_basis, basis_type="RI_XAS")
    2967           0 :       CALL get_gto_basis_set(ri_basis, nset=nset, maxso=maxso, nsgf=ri_nsgf)
    2968           0 :       nsotot = nset*maxso
    2969           0 :       ri_sphi_so => xas_atom_env%ri_sphi_so(ikind)%array
    2970           0 :       rhoa => rho_set%rhoa
    2971           0 :       rhob => rho_set%rhob
    2972             : 
    2973           0 :       ALLOCATE (d1e(2))
    2974           0 :       deriv => xc_dset_get_derivative(deriv_set, [deriv_rhoa])
    2975           0 :       CALL xc_derivative_get(deriv, deriv_data=d1e(1)%array)
    2976           0 :       deriv => xc_dset_get_derivative(deriv_set, [deriv_rhob])
    2977           0 :       CALL xc_derivative_get(deriv, deriv_data=d1e(2)%array)
    2978             : 
    2979             :       ! In case rhoa -> rhob, take the limit, which involves the (already computed) second derivatives
    2980           0 :       ALLOCATE (d2e(3))
    2981           0 :       deriv => xc_dset_get_derivative(deriv_set, [deriv_rhoa, deriv_rhoa])
    2982           0 :       CALL xc_derivative_get(deriv, deriv_data=d2e(1)%array)
    2983           0 :       deriv => xc_dset_get_derivative(deriv_set, [deriv_rhoa, deriv_rhob])
    2984           0 :       CALL xc_derivative_get(deriv, deriv_data=d2e(2)%array)
    2985           0 :       deriv => xc_dset_get_derivative(deriv_set, [deriv_rhob, deriv_rhob])
    2986           0 :       CALL xc_derivative_get(deriv, deriv_data=d2e(3)%array)
    2987             : 
    2988             :       !Compute the kernel on the grid. Already take weight into acocunt there
    2989           0 :       ALLOCATE (fxc(na, nr))
    2990             : !$OMP PARALLEL DO COLLAPSE(2) SCHEDULE(STATIC) DEFAULT(NONE), &
    2991             : !$OMP SHARED(grid_atom,fxc,d1e,d2e,dft_control,na,nr,rhoa,rhob), &
    2992           0 : !$OMP PRIVATE(ia,ir)
    2993             :       DO ir = 1, nr
    2994             :          DO ia = 1, na
    2995             : 
    2996             :             !Need to be careful not to divide by zero. Assume that if rhoa == rhob, then
    2997             :             !take the limit fxc = 0.5* (f_aa + f_bb - 2f_ab)
    2998             :             IF (ABS(rhoa(ia, ir, 1) - rhob(ia, ir, 1)) > dft_control%qs_control%eps_rho_rspace) THEN
    2999             :                fxc(ia, ir) = grid_atom%weight(ia, ir)/(rhoa(ia, ir, 1) - rhob(ia, ir, 1)) &
    3000             :                              *(d1e(1)%array(ia, ir, 1) - d1e(2)%array(ia, ir, 1))
    3001             :             ELSE
    3002             :                fxc(ia, ir) = 0.5_dp*grid_atom%weight(ia, ir)* &
    3003             :                              (d2e(1)%array(ia, ir, 1) + d2e(3)%array(ia, ir, 1) - 2._dp*d2e(2)%array(ia, ir, 1))
    3004             :             END IF
    3005             : 
    3006             :          END DO
    3007             :       END DO
    3008             : !$OMP END PARALLEL DO
    3009             : 
    3010             :       ! Integrate wrt to so
    3011           0 :       ALLOCATE (int_so(nsotot, nsotot))
    3012           0 :       int_so = 0.0_dp
    3013           0 :       CALL integrate_so_prod(int_so, fxc, ikind, xas_atom_env, qs_env)
    3014             : 
    3015             :       ! Contract into sgf. Array located on current processor only
    3016           0 :       ALLOCATE (int_fxc(iatom, 4)%array(ri_nsgf, ri_nsgf))
    3017           0 :       int_fxc(iatom, 4)%array = 0.0_dp
    3018           0 :       CALL contract_so2sgf(int_fxc(iatom, 4)%array, int_so, ri_basis, ri_sphi_so)
    3019             : 
    3020           0 :    END SUBROUTINE integrate_sf_fxc
    3021             : 
    3022             : ! **************************************************************************************************
    3023             : !> \brief Contract spherical orbitals to spherical Gaussians (so to sgf)
    3024             : !> \param int_sgf the array with the sgf integrals
    3025             : !> \param int_so the array with the so integrals (to contract)
    3026             : !> \param basis the corresponding gto basis set
    3027             : !> \param sphi_so the contraction coefficients for the s:
    3028             : ! **************************************************************************************************
    3029         248 :    SUBROUTINE contract_so2sgf(int_sgf, int_so, basis, sphi_so)
    3030             : 
    3031             :       REAL(dp), DIMENSION(:, :)                          :: int_sgf, int_so
    3032             :       TYPE(gto_basis_set_type), POINTER                  :: basis
    3033             :       REAL(dp), DIMENSION(:, :)                          :: sphi_so
    3034             : 
    3035             :       INTEGER                                            :: iset, jset, maxso, nset, nsoi, nsoj, &
    3036             :                                                             sgfi, sgfj, starti, startj
    3037         248 :       INTEGER, DIMENSION(:), POINTER                     :: lmax, npgf, nsgf_set
    3038         248 :       INTEGER, DIMENSION(:, :), POINTER                  :: first_sgf
    3039             : 
    3040         248 :       NULLIFY (nsgf_set, npgf, lmax, first_sgf)
    3041             : 
    3042             :       CALL get_gto_basis_set(basis, nset=nset, maxso=maxso, nsgf_set=nsgf_set, first_sgf=first_sgf, &
    3043         248 :                              npgf=npgf, lmax=lmax)
    3044             : 
    3045        1156 :       DO iset = 1, nset
    3046         908 :          starti = (iset - 1)*maxso + 1
    3047         908 :          nsoi = npgf(iset)*nsoset(lmax(iset))
    3048         908 :          sgfi = first_sgf(1, iset)
    3049             : 
    3050        7268 :          DO jset = 1, nset
    3051        6112 :             startj = (jset - 1)*maxso + 1
    3052        6112 :             nsoj = npgf(jset)*nsoset(lmax(jset))
    3053        6112 :             sgfj = first_sgf(1, jset)
    3054             : 
    3055             :             CALL ab_contract(int_sgf(sgfi:sgfi + nsgf_set(iset) - 1, sgfj:sgfj + nsgf_set(jset) - 1), &
    3056             :                              int_so(starti:starti + nsoi - 1, startj:startj + nsoj - 1), &
    3057             :                              sphi_so(:, sgfi:), sphi_so(:, sgfj:), nsoi, nsoj, &
    3058        7020 :                              nsgf_set(iset), nsgf_set(jset))
    3059             :          END DO !jset
    3060             :       END DO !iset
    3061             : 
    3062         248 :    END SUBROUTINE contract_so2sgf
    3063             : 
    3064             : ! **************************************************************************************************
    3065             : !> \brief Integrate the product of spherical gaussian orbitals with the xc kernel on the atomic grid
    3066             : !> \param intso the integral in terms of spherical orbitals
    3067             : !> \param fxc the xc kernel at each grid point
    3068             : !> \param ikind the kind of the atom we integrate for
    3069             : !> \param xas_atom_env ...
    3070             : !> \param qs_env ...
    3071             : !> \note Largely copied from gaVxcgb_noGC. Rewritten here because we need our own atomic grid,
    3072             : !>       harmonics, basis set and we do not need the soft vxc. Could have tweaked the original, but
    3073             : !>       it would have been messy. Also we do not need rho_atom (too big and fancy for us)
    3074             : !>       We also go over the whole range of angular momentum l
    3075             : ! **************************************************************************************************
    3076          78 :    SUBROUTINE integrate_so_prod(intso, fxc, ikind, xas_atom_env, qs_env)
    3077             : 
    3078             :       REAL(dp), DIMENSION(:, :), INTENT(INOUT)           :: intso
    3079             :       REAL(dp), DIMENSION(:, :), INTENT(IN)              :: fxc
    3080             :       INTEGER, INTENT(IN)                                :: ikind
    3081             :       TYPE(xas_atom_env_type), POINTER                   :: xas_atom_env
    3082             :       TYPE(qs_environment_type), POINTER                 :: qs_env
    3083             : 
    3084             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'integrate_so_prod'
    3085             : 
    3086             :       INTEGER :: handle, ia, ic, icg, ipgf1, ipgf2, iset1, iset2, iso, iso1, iso2, l, ld, lmax12, &
    3087             :          lmin12, m1, m2, max_iso_not0, max_iso_not0_local, max_s_harm, maxl, maxso, n1, n2, na, &
    3088             :          ngau1, ngau2, nngau1, nr, nset, size1
    3089             :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: cg_n_list
    3090             :       INTEGER, ALLOCATABLE, DIMENSION(:, :, :)           :: cg_list
    3091          78 :       INTEGER, DIMENSION(:), POINTER                     :: lmax, lmin, npgf
    3092          78 :       REAL(dp), ALLOCATABLE, DIMENSION(:)                :: g1, g2
    3093          78 :       REAL(dp), ALLOCATABLE, DIMENSION(:, :)             :: gfxcg, gg, matso
    3094          78 :       REAL(dp), DIMENSION(:, :), POINTER                 :: zet
    3095             :       REAL(dp), DIMENSION(:, :, :), POINTER              :: my_CG
    3096             :       TYPE(grid_atom_type), POINTER                      :: grid_atom
    3097             :       TYPE(gto_basis_set_type), POINTER                  :: ri_basis
    3098             :       TYPE(harmonics_atom_type), POINTER                 :: harmonics
    3099          78 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
    3100             : 
    3101          78 :       CALL timeset(routineN, handle)
    3102             : 
    3103          78 :       NULLIFY (grid_atom, harmonics, ri_basis, qs_kind_set, lmax, lmin, npgf, zet, my_CG)
    3104             : 
    3105             : !  Initialization
    3106          78 :       CALL get_qs_env(qs_env, qs_kind_set=qs_kind_set)
    3107          78 :       CALL get_qs_kind(qs_kind_set(ikind), basis_set=ri_basis, basis_type="RI_XAS")
    3108          78 :       grid_atom => xas_atom_env%grid_atom_set(ikind)%grid_atom
    3109          78 :       harmonics => xas_atom_env%harmonics_atom_set(ikind)%harmonics_atom
    3110             : 
    3111             :       CALL get_gto_basis_set(ri_basis, lmax=lmax, lmin=lmin, maxso=maxso, maxl=maxl, npgf=npgf, &
    3112          78 :                              nset=nset, zet=zet)
    3113             : 
    3114          78 :       na = grid_atom%ng_sphere
    3115          78 :       nr = grid_atom%nr
    3116          78 :       my_CG => harmonics%my_CG
    3117          78 :       max_iso_not0 = harmonics%max_iso_not0
    3118          78 :       max_s_harm = harmonics%max_s_harm
    3119          78 :       CPASSERT(2*maxl .LE. indso(1, max_iso_not0))
    3120             : 
    3121         546 :       ALLOCATE (g1(nr), g2(nr), gg(nr, 0:2*maxl))
    3122         312 :       ALLOCATE (gfxcg(na, 0:2*maxl))
    3123         312 :       ALLOCATE (matso(nsoset(maxl), nsoset(maxl)))
    3124         468 :       ALLOCATE (cg_list(2, nsoset(maxl)**2, max_s_harm), cg_n_list(max_s_harm))
    3125             : 
    3126       10466 :       g1 = 0.0_dp
    3127       10466 :       g2 = 0.0_dp
    3128          78 :       m1 = 0
    3129             : !  Loop over the product of so
    3130         310 :       DO iset1 = 1, nset
    3131         232 :          n1 = nsoset(lmax(iset1))
    3132         232 :          m2 = 0
    3133        2292 :          DO iset2 = 1, nset
    3134             :             CALL get_none0_cg_list(my_CG, lmin(iset1), lmax(iset1), lmin(iset2), lmax(iset2), &
    3135             :                                    max_s_harm, lmax(iset1) + lmax(iset2), cg_list, cg_n_list, &
    3136        2060 :                                    max_iso_not0_local)
    3137        2060 :             CPASSERT(max_iso_not0_local .LE. max_iso_not0)
    3138             : 
    3139        2060 :             n2 = nsoset(lmax(iset2))
    3140        6128 :             DO ipgf1 = 1, npgf(iset1)
    3141        4068 :                ngau1 = n1*(ipgf1 - 1) + m1
    3142        4068 :                size1 = nsoset(lmax(iset1)) - nsoset(lmin(iset1) - 1)
    3143        4068 :                nngau1 = nsoset(lmin(iset1) - 1) + ngau1
    3144             : 
    3145      635428 :                g1(:) = EXP(-zet(ipgf1, iset1)*grid_atom%rad2(1:nr))
    3146       26196 :                DO ipgf2 = 1, npgf(iset2)
    3147       20068 :                   ngau2 = n2*(ipgf2 - 1) + m2
    3148             : 
    3149     2615870 :                   g2(:) = EXP(-zet(ipgf2, iset2)*grid_atom%rad2(1:nr))
    3150       20068 :                   lmin12 = lmin(iset1) + lmin(iset2)
    3151       20068 :                   lmax12 = lmax(iset1) + lmax(iset2)
    3152             : 
    3153             :                   !get the gaussian product
    3154    18015114 :                   gg = 0.0_dp
    3155       20068 :                   IF (lmin12 == 0) THEN
    3156     1461044 :                      gg(:, lmin12) = g1(:)*g2(:)
    3157             :                   ELSE
    3158     1154826 :                      gg(:, lmin12) = grid_atom%rad2l(1:nr, lmin12)*g1(:)*g2(:)
    3159             :                   END IF
    3160             : 
    3161       60612 :                   DO l = lmin12 + 1, lmax12
    3162     5473172 :                      gg(:, l) = grid_atom%rad(1:nr)*gg(:, l - 1)
    3163             :                   END DO
    3164             : 
    3165       20068 :                   ld = lmax12 + 1
    3166             :                   CALL dgemm('N', 'N', na, ld, nr, 1.0_dp, fxc(1:na, 1:nr), na, gg(:, 0:lmax12), &
    3167       20068 :                              nr, 0.0_dp, gfxcg(1:na, 0:lmax12), na)
    3168             : 
    3169             :                   !integrate
    3170     6160324 :                   matso = 0.0_dp
    3171      404316 :                   DO iso = 1, max_iso_not0_local
    3172     2092858 :                      DO icg = 1, cg_n_list(iso)
    3173     1688542 :                         iso1 = cg_list(1, icg, iso)
    3174     1688542 :                         iso2 = cg_list(2, icg, iso)
    3175     1688542 :                         l = indso(1, iso1) + indso(1, iso2)
    3176             : 
    3177   345611978 :                         DO ia = 1, na
    3178             :                            matso(iso1, iso2) = matso(iso1, iso2) + gfxcg(ia, l)* &
    3179   345227730 :                                                my_CG(iso1, iso2, iso)*harmonics%slm(ia, iso)
    3180             :                         END DO !ia
    3181             :                      END DO !icg
    3182             :                   END DO !iso
    3183             : 
    3184             :                   !write in integral matrix
    3185      142036 :                   DO ic = nsoset(lmin(iset2) - 1) + 1, nsoset(lmax(iset2))
    3186      117900 :                      iso1 = nsoset(lmin(iset1) - 1) + 1
    3187      117900 :                      iso2 = ngau2 + ic
    3188      137968 :                      CALL daxpy(size1, 1.0_dp, matso(iso1:, ic), 1, intso(nngau1 + 1:, iso2), 1)
    3189             :                   END DO !ic
    3190             : 
    3191             :                END DO !ipgf2
    3192             :             END DO ! ipgf1
    3193        2292 :             m2 = m2 + maxso
    3194             :          END DO !iset2
    3195         310 :          m1 = m1 + maxso
    3196             :       END DO !iset1
    3197             : 
    3198          78 :       CALL timestop(handle)
    3199             : 
    3200         234 :    END SUBROUTINE integrate_so_prod
    3201             : 
    3202             : ! **************************************************************************************************
    3203             : !> \brief This routine computes the integral of a potential V wrt the derivative of the spherical
    3204             : !>        orbitals, that is <df/dx|V|dg/dy> on the atomic grid.
    3205             : !> \param intso the integral in terms of the spherical orbitals (well, their derivative)
    3206             : !> \param V the potential (put on the grid and weighted) to integrate
    3207             : !> \param ikind the atomic kind for which we integrate
    3208             : !> \param qs_env ...
    3209             : !> \param soc_atom_env ...
    3210             : ! **************************************************************************************************
    3211          44 :    SUBROUTINE integrate_so_dxdy_prod(intso, V, ikind, qs_env, soc_atom_env)
    3212             : 
    3213             :       REAL(dp), DIMENSION(:, :, :), INTENT(INOUT)        :: intso
    3214             :       REAL(dp), DIMENSION(:, :), INTENT(IN)              :: V
    3215             :       INTEGER, INTENT(IN)                                :: ikind
    3216             :       TYPE(qs_environment_type), POINTER                 :: qs_env
    3217             :       TYPE(soc_atom_env_type), OPTIONAL, POINTER         :: soc_atom_env
    3218             : 
    3219             :       INTEGER                                            :: i, ipgf, iset, iso, j, jpgf, jset, jso, &
    3220             :                                                             k, l, maxso, na, nr, nset, starti, &
    3221             :                                                             startj
    3222          44 :       INTEGER, DIMENSION(:), POINTER                     :: lmax, lmin, npgf
    3223          44 :       REAL(dp), ALLOCATABLE, DIMENSION(:, :)             :: fga, fgr, r1, r2, work
    3224          44 :       REAL(dp), ALLOCATABLE, DIMENSION(:, :, :)          :: a1, a2
    3225          44 :       REAL(dp), DIMENSION(:, :), POINTER                 :: slm, zet
    3226          44 :       REAL(dp), DIMENSION(:, :, :), POINTER              :: dslm_dxyz
    3227             :       TYPE(grid_atom_type), POINTER                      :: grid_atom
    3228             :       TYPE(gto_basis_set_type), POINTER                  :: basis
    3229             :       TYPE(harmonics_atom_type), POINTER                 :: harmonics
    3230          44 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
    3231             : 
    3232          44 :       NULLIFY (grid_atom, harmonics, basis, qs_kind_set, dslm_dxyz, slm, lmin, lmax, npgf, zet)
    3233             : 
    3234          44 :       CALL get_qs_env(qs_env, qs_kind_set=qs_kind_set)
    3235          44 :       CALL get_qs_kind(qs_kind_set(ikind), basis_set=basis, basis_type="ORB")
    3236          44 :       IF (PRESENT(soc_atom_env)) THEN
    3237           8 :          grid_atom => soc_atom_env%grid_atom_set(ikind)%grid_atom
    3238           8 :          harmonics => soc_atom_env%harmonics_atom_set(ikind)%harmonics_atom
    3239             :       ELSE
    3240             :          CALL get_qs_kind(qs_kind_set(ikind), basis_set=basis, basis_type="ORB", harmonics=harmonics, &
    3241          36 :                           grid_atom=grid_atom)
    3242             :       END IF
    3243             : 
    3244          44 :       na = grid_atom%ng_sphere
    3245          44 :       nr = grid_atom%nr
    3246             : 
    3247          44 :       slm => harmonics%slm
    3248          44 :       dslm_dxyz => harmonics%dslm_dxyz
    3249             : 
    3250             : !  Getting what we need from the orbital basis
    3251             :       CALL get_gto_basis_set(gto_basis_set=basis, lmax=lmax, lmin=lmin, &
    3252          44 :                              maxso=maxso, npgf=npgf, nset=nset, zet=zet)
    3253             : 
    3254             : !  Separate the functions into purely r and purely angular parts, compute them all
    3255             : !  and use matrix mutliplication for the integral. We use f for x derivative and g for y
    3256             : 
    3257             :       ! Separating the functions. Note that the radial part is the same for x and y derivatives
    3258         308 :       ALLOCATE (a1(na, nset*maxso, 3), a2(na, nset*maxso, 3))
    3259         264 :       ALLOCATE (r1(nr, nset*maxso), r2(nr, nset*maxso))
    3260      929324 :       a1 = 0.0_dp; a2 = 0.0_dp
    3261      299588 :       r1 = 0.0_dp; r2 = 0.0_dp
    3262             : 
    3263         244 :       DO iset = 1, nset
    3264         722 :          DO ipgf = 1, npgf(iset)
    3265         478 :             starti = (iset - 1)*maxso + (ipgf - 1)*nsoset(lmax(iset))
    3266        1930 :             DO iso = nsoset(lmin(iset) - 1) + 1, nsoset(lmax(iset))
    3267        1252 :                l = indso(1, iso)
    3268             : 
    3269             :                ! The x derivative of the spherical orbital, divided in angular and radial parts
    3270             :                ! Two of each are needed because d/dx(r^l Y_lm) * exp(-al*r^2) + r^l Y_lm * ! d/dx(exp-al*r^2)
    3271             : 
    3272             :                ! the purely radial part of d/dx(r^l Y_lm) * exp(-al*r^2) (same for y)
    3273       61182 :                r1(1:nr, starti + iso) = grid_atom%rad(1:nr)**(l - 1)*EXP(-zet(ipgf, iset)*grid_atom%rad2(1:nr))
    3274             : 
    3275             :                ! the purely radial part of r^l Y_lm * d/dx(exp-al*r^2) (same for y)
    3276             :                r2(1:nr, starti + iso) = -2.0_dp*zet(ipgf, iset)*grid_atom%rad(1:nr)**(l + 1) &
    3277       61182 :                                         *EXP(-zet(ipgf, iset)*grid_atom%rad2(1:nr))
    3278             : 
    3279        5486 :                DO i = 1, 3
    3280             :                   ! the purely angular part of d/dx(r^l Y_lm) * exp(-al*r^2)
    3281      191556 :                   a1(1:na, starti + iso, i) = dslm_dxyz(i, 1:na, iso)
    3282             : 
    3283             :                   ! the purely angular part of r^l Y_lm * d/dx(exp-al*r^2)
    3284      192808 :                   a2(1:na, starti + iso, i) = harmonics%a(i, 1:na)*slm(1:na, iso)
    3285             :                END DO
    3286             : 
    3287             :             END DO !iso
    3288             :          END DO !ipgf
    3289             :       END DO !iset
    3290             : 
    3291             :       ! Do the integration in terms of so using matrix products
    3292     1308380 :       intso = 0.0_dp
    3293         132 :       ALLOCATE (fga(na, 1))
    3294         132 :       ALLOCATE (fgr(nr, 1))
    3295          88 :       ALLOCATE (work(na, 1))
    3296        6714 :       fga = 0.0_dp; fgr = 0.0_dp; work = 0.0_dp
    3297             : 
    3298         244 :       DO iset = 1, nset
    3299        1544 :          DO jset = 1, nset
    3300        4470 :             DO ipgf = 1, npgf(iset)
    3301        2970 :                starti = (iset - 1)*maxso + (ipgf - 1)*nsoset(lmax(iset))
    3302       11472 :                DO jpgf = 1, npgf(jset)
    3303        7202 :                   startj = (jset - 1)*maxso + (jpgf - 1)*nsoset(lmax(jset))
    3304             : 
    3305       31778 :                   DO i = 1, 3
    3306       21606 :                      j = MOD(i, 3) + 1
    3307       21606 :                      k = MOD(i + 1, 3) + 1
    3308             : 
    3309       84584 :                      DO iso = nsoset(lmin(iset) - 1) + 1, nsoset(lmax(iset))
    3310      234174 :                         DO jso = nsoset(lmin(jset) - 1) + 1, nsoset(lmax(jset))
    3311             : 
    3312             :                            !Two component per function => 4 terms in total
    3313             : 
    3314             :                            ! take r1*a1(j) * V * r1*a1(k)
    3315     7624818 :                            fgr(1:nr, 1) = r1(1:nr, starti + iso)*r1(1:nr, startj + jso)
    3316     7996392 :                            fga(1:na, 1) = a1(1:na, starti + iso, j)*a1(1:na, startj + jso, k)
    3317             : 
    3318      156792 :                            CALL dgemm('N', 'N', na, 1, nr, 1.0_dp, V, na, fgr, nr, 0.0_dp, work, na)
    3319             :                            CALL dgemm('T', 'N', 1, 1, na, 1.0_dp, work, na, fga, na, 0.0_dp, &
    3320      156792 :                                       intso(starti + iso:, startj + jso, i), 1)
    3321             : 
    3322             :                            ! add r1*a1(j) * V * r2*a2(k)
    3323     7624818 :                            fgr(1:nr, 1) = r1(1:nr, starti + iso)*r2(1:nr, startj + jso)
    3324     7996392 :                            fga(1:na, 1) = a1(1:na, starti + iso, j)*a2(1:na, startj + jso, k)
    3325             : 
    3326      156792 :                            CALL dgemm('N', 'N', na, 1, nr, 1.0_dp, V, na, fgr, nr, 0.0_dp, work, na)
    3327             :                            CALL dgemm('T', 'N', 1, 1, na, 1.0_dp, work, na, fga, na, 1.0_dp, &
    3328      156792 :                                       intso(starti + iso:, startj + jso, i), 1)
    3329             : 
    3330             :                            ! add r2*a2(j) * V * r1*a1(k)
    3331     7624818 :                            fgr(1:nr, 1) = r2(1:nr, starti + iso)*r1(1:nr, startj + jso)
    3332     7996392 :                            fga(1:na, 1) = a2(1:na, starti + iso, j)*a1(1:na, startj + jso, k)
    3333             : 
    3334      156792 :                            CALL dgemm('N', 'N', na, 1, nr, 1.0_dp, V, na, fgr, nr, 0.0_dp, work, na)
    3335             :                            CALL dgemm('T', 'N', 1, 1, na, 1.0_dp, work, na, fga, na, 1.0_dp, &
    3336      156792 :                                       intso(starti + iso:, startj + jso, i), 1)
    3337             : 
    3338             :                            ! add the last term: r2*a2(j) * V * r2*a2(k)
    3339     7624818 :                            fgr(1:nr, 1) = r2(1:nr, starti + iso)*r2(1:nr, startj + jso)
    3340     7996392 :                            fga(1:na, 1) = a2(1:na, starti + iso, j)*a2(1:na, startj + jso, k)
    3341             : 
    3342      156792 :                            CALL dgemm('N', 'N', na, 1, nr, 1.0_dp, V, na, fgr, nr, 0.0_dp, work, na)
    3343             :                            CALL dgemm('T', 'N', 1, 1, na, 1.0_dp, work, na, fga, na, 1.0_dp, &
    3344      212568 :                                       intso(starti + iso:, startj + jso, i), 1)
    3345             : 
    3346             :                         END DO !jso
    3347             :                      END DO !iso
    3348             : 
    3349             :                   END DO !i
    3350             :                END DO !jpgf
    3351             :             END DO !ipgf
    3352             :          END DO !jset
    3353             :       END DO !iset
    3354             : 
    3355         176 :       DO i = 1, 3
    3356     2616584 :          intso(:, :, i) = intso(:, :, i) - TRANSPOSE(intso(:, :, i))
    3357             :       END DO
    3358             : 
    3359         132 :    END SUBROUTINE integrate_so_dxdy_prod
    3360             : 
    3361             : ! **************************************************************************************************
    3362             : !> \brief Computes the SOC matrix elements with respect to the ORB basis set for each atomic kind
    3363             : !>        and put them as the block diagonal of dbcsr_matrix
    3364             : !> \param matrix_soc the matrix where the SOC is stored
    3365             : !> \param xas_atom_env ...
    3366             : !> \param qs_env ...
    3367             : !> \param soc_atom_env ...
    3368             : !> \note We compute: <da_dx|V\(4c^2-2V)|db_dy> - <da_dy|V\(4c^2-2V)|db_dx>, where V is a model
    3369             : !>       potential on the atomic grid. What we get is purely imaginary
    3370             : ! **************************************************************************************************
    3371          30 :    SUBROUTINE integrate_soc_atoms(matrix_soc, xas_atom_env, qs_env, soc_atom_env)
    3372             : 
    3373             :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_soc
    3374             :       TYPE(xas_atom_env_type), OPTIONAL, POINTER         :: xas_atom_env
    3375             :       TYPE(qs_environment_type), POINTER                 :: qs_env
    3376             :       TYPE(soc_atom_env_type), OPTIONAL, POINTER         :: soc_atom_env
    3377             : 
    3378             :       CHARACTER(len=*), PARAMETER :: routineN = 'integrate_soc_atoms'
    3379             : 
    3380             :       INTEGER                                            :: handle, i, iat, ikind, ir, jat, maxso, &
    3381             :                                                             na, nkind, nr, nset, nsgf
    3382             :       LOGICAL                                            :: all_potential_present
    3383             :       REAL(dp)                                           :: zeff
    3384          30 :       REAL(dp), ALLOCATABLE, DIMENSION(:)                :: Vr
    3385          30 :       REAL(dp), ALLOCATABLE, DIMENSION(:, :)             :: V
    3386          30 :       REAL(dp), ALLOCATABLE, DIMENSION(:, :, :)          :: intso
    3387          30 :       REAL(dp), DIMENSION(:, :), POINTER                 :: sphi_so
    3388          30 :       REAL(dp), DIMENSION(:, :, :), POINTER              :: intsgf
    3389          30 :       TYPE(cp_3d_r_p_type), DIMENSION(:), POINTER        :: int_soc
    3390             :       TYPE(dbcsr_iterator_type)                          :: iter
    3391          30 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_s
    3392             :       TYPE(grid_atom_type), POINTER                      :: grid
    3393             :       TYPE(gto_basis_set_type), POINTER                  :: basis
    3394          30 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
    3395          30 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
    3396             : 
    3397             : !!DEBUG
    3398          30 :       CALL timeset(routineN, handle)
    3399             : 
    3400          30 :       NULLIFY (int_soc, basis, qs_kind_set, sphi_so, matrix_s, grid)
    3401          30 :       NULLIFY (particle_set)
    3402             : 
    3403             :       !  Initialization
    3404             :       CALL get_qs_env(qs_env, nkind=nkind, qs_kind_set=qs_kind_set, matrix_s=matrix_s, &
    3405          30 :                       particle_set=particle_set)
    3406             : 
    3407             :       ! all_potential_present
    3408          30 :       CALL get_qs_kind_set(qs_kind_set, all_potential_present=all_potential_present)
    3409             : 
    3410             :       ! Loop over the kinds to compute the integrals
    3411         134 :       ALLOCATE (int_soc(nkind))
    3412          74 :       DO ikind = 1, nkind
    3413          44 :          CALL get_qs_kind(qs_kind_set(ikind), basis_set=basis, basis_type="ORB", zeff=zeff)
    3414          44 :          IF (PRESENT(soc_atom_env)) THEN
    3415           8 :             grid => soc_atom_env%grid_atom_set(ikind)%grid_atom
    3416             :          ELSE
    3417          36 :             CALL get_qs_kind(qs_kind_set(ikind), grid_atom=grid)
    3418             :          END IF
    3419          44 :          CALL get_gto_basis_set(basis, nset=nset, maxso=maxso)
    3420         220 :          ALLOCATE (intso(nset*maxso, nset*maxso, 3))
    3421             : 
    3422             :          ! compute the model potential on the grid
    3423          44 :          nr = grid%nr
    3424          44 :          na = grid%ng_sphere
    3425             : 
    3426         132 :          ALLOCATE (Vr(nr))
    3427          44 :          CALL calculate_model_potential(Vr, grid, zeff)
    3428             : 
    3429             :          ! Compute V/(4c^2-2V) and weight it
    3430         176 :          ALLOCATE (V(na, nr))
    3431      109082 :          V = 0.0_dp
    3432        2182 :          DO ir = 1, nr
    3433             :             CALL daxpy(na, Vr(ir)/(4.0_dp*c_light_au**2 - 2.0_dp*Vr(ir)), grid%weight(:, ir), 1, &
    3434        2182 :                        V(:, ir), 1)
    3435             :          END DO
    3436          44 :          DEALLOCATE (Vr)
    3437             : 
    3438             :          ! compute the integral <da_dx|...|db_dy> in terms of so
    3439          44 :          IF (PRESENT(xas_atom_env)) THEN
    3440          36 :             CALL integrate_so_dxdy_prod(intso, V, ikind, qs_env)
    3441             :          ELSE
    3442           8 :             CALL integrate_so_dxdy_prod(intso, V, ikind, qs_env, soc_atom_env)
    3443             :          END IF
    3444          44 :          DEALLOCATE (V)
    3445             : 
    3446             :          ! contract in terms of sgf
    3447          44 :          CALL get_gto_basis_set(basis, nsgf=nsgf)
    3448         220 :          ALLOCATE (int_soc(ikind)%array(nsgf, nsgf, 3))
    3449          44 :          intsgf => int_soc(ikind)%array
    3450          44 :          IF (PRESENT(xas_atom_env)) THEN
    3451          36 :             sphi_so => xas_atom_env%orb_sphi_so(ikind)%array
    3452             :          ELSE
    3453           8 :             sphi_so => soc_atom_env%orb_sphi_so(ikind)%array
    3454             :          END IF
    3455       35888 :          intsgf = 0.0_dp
    3456             : 
    3457         176 :          DO i = 1, 3
    3458         176 :             CALL contract_so2sgf(intsgf(:, :, i), intso(:, :, i), basis, sphi_so)
    3459             :          END DO
    3460             : 
    3461         206 :          DEALLOCATE (intso)
    3462             :       END DO !ikind
    3463             : 
    3464             :       ! Build the matrix_soc based on the matrix_s (but anti-symmetric)
    3465          30 :       IF ((PRESENT(xas_atom_env)) .OR. all_potential_present) THEN
    3466         112 :          DO i = 1, 3
    3467             :             CALL dbcsr_create(matrix_soc(i)%matrix, name="SOC MATRIX", template=matrix_s(1)%matrix, &
    3468         112 :                               matrix_type=dbcsr_type_antisymmetric)
    3469             :          END DO
    3470             :          !  Iterate over its diagonal blocks and fill=it
    3471          28 :          CALL dbcsr_iterator_start(iter, matrix_s(1)%matrix)
    3472         158 :          DO WHILE (dbcsr_iterator_blocks_left(iter))
    3473             : 
    3474         130 :             CALL dbcsr_iterator_next_block(iter, row=iat, column=jat)
    3475         130 :             IF (.NOT. iat == jat) CYCLE
    3476          46 :             ikind = particle_set(iat)%atomic_kind%kind_number
    3477             : 
    3478         212 :             DO i = 1, 3
    3479         268 :                CALL dbcsr_put_block(matrix_soc(i)%matrix, iat, iat, int_soc(ikind)%array(:, :, i))
    3480             :             END DO
    3481             : 
    3482             :          END DO !iat
    3483          28 :          CALL dbcsr_iterator_stop(iter)
    3484             :       ELSE  ! pseudopotentials here
    3485           8 :          DO i = 1, 3
    3486             :             CALL dbcsr_create(matrix_soc(i)%matrix, name="SOC MATRIX", template=matrix_s(1)%matrix, &
    3487           6 :                               matrix_type=dbcsr_type_no_symmetry)
    3488           6 :             CALL dbcsr_set(matrix_soc(i)%matrix, 0.0_dp)
    3489           8 :             CALL dbcsr_copy(matrix_soc(i)%matrix, soc_atom_env%soc_pp(i, 1)%matrix)
    3490             :          END DO
    3491             :       END IF
    3492             : 
    3493         120 :       DO i = 1, 3
    3494         120 :          CALL dbcsr_finalize(matrix_soc(i)%matrix)
    3495             :       END DO
    3496             : 
    3497             :       ! Clean-up
    3498          74 :       DO ikind = 1, nkind
    3499          74 :          DEALLOCATE (int_soc(ikind)%array)
    3500             :       END DO
    3501          30 :       DEALLOCATE (int_soc)
    3502             : 
    3503          30 :       CALL timestop(handle)
    3504             : 
    3505          90 :    END SUBROUTINE integrate_soc_atoms
    3506             : 
    3507             : END MODULE xas_tdp_atom

Generated by: LCOV version 1.15