LCOV - code coverage report
Current view: top level - src - qs_cneo_methods.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:936074a) Lines: 95.6 % 637 609
Test Date: 2025-12-04 06:27:48 Functions: 100.0 % 7 7

            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 A collection of functions used by CNEO-DFT
      10              : !>      (see J. Chem. Theory Comput. 2025, 21, 16, 7865–7877)
      11              : !> \par History
      12              : !>      08.2025 created [zc62]
      13              : !> \author Zehua Chen
      14              : ! **************************************************************************************************
      15              : MODULE qs_cneo_methods
      16              :    USE ai_verfc,                        ONLY: verfc
      17              :    USE ao_util,                         ONLY: trace_r_AxB
      18              :    USE atom_operators,                  ONLY: atom_int_release,&
      19              :                                               atom_int_setup
      20              :    USE atom_types,                      ONLY: CGTO_BASIS,&
      21              :                                               atom_basis_type,&
      22              :                                               atom_integrals,&
      23              :                                               lmat,&
      24              :                                               release_atom_basis
      25              :    USE atomic_kind_types,               ONLY: atomic_kind_type,&
      26              :                                               get_atomic_kind,&
      27              :                                               get_atomic_kind_set
      28              :    USE basis_set_types,                 ONLY: get_gto_basis_set,&
      29              :                                               gto_basis_set_type
      30              :    USE bibliography,                    ONLY: Chen2025,&
      31              :                                               cite_reference
      32              :    USE core_ae,                         ONLY: verfc_force
      33              :    USE cp_control_types,                ONLY: gapw_control_type
      34              :    USE cp_log_handling,                 ONLY: cp_to_string
      35              :    USE distribution_1d_types,           ONLY: distribution_1d_type
      36              :    USE kinds,                           ONLY: dp
      37              :    USE mathconstants,                   ONLY: dfac,&
      38              :                                               fourpi,&
      39              :                                               pi
      40              :    USE mathlib,                         ONLY: get_pseudo_inverse_svd
      41              :    USE memory_utilities,                ONLY: reallocate
      42              :    USE message_passing,                 ONLY: mp_para_env_type
      43              :    USE orbital_pointers,                ONLY: indso,&
      44              :                                               indso_inv,&
      45              :                                               init_orbital_pointers,&
      46              :                                               ncoset,&
      47              :                                               nso,&
      48              :                                               nsoset
      49              :    USE particle_types,                  ONLY: particle_type
      50              :    USE physcon,                         ONLY: massunit
      51              :    USE qs_cneo_types,                   ONLY: allocate_rhoz_cneo_set,&
      52              :                                               cneo_potential_type,&
      53              :                                               get_cneo_potential,&
      54              :                                               rhoz_cneo_type,&
      55              :                                               set_cneo_potential
      56              :    USE qs_cneo_utils,                   ONLY: atom_solve_cneo,&
      57              :                                               cneo_gather,&
      58              :                                               create_harmonics_atom_cneo,&
      59              :                                               create_my_CG_cneo,&
      60              :                                               get_maxl_CG_cneo
      61              :    USE qs_environment_types,            ONLY: get_qs_env,&
      62              :                                               qs_environment_type
      63              :    USE qs_force_types,                  ONLY: qs_force_type
      64              :    USE qs_grid_atom,                    ONLY: allocate_grid_atom,&
      65              :                                               grid_atom_type
      66              :    USE qs_harmonics_atom,               ONLY: allocate_harmonics_atom,&
      67              :                                               get_none0_cg_list,&
      68              :                                               harmonics_atom_type
      69              :    USE qs_kind_types,                   ONLY: get_qs_kind,&
      70              :                                               get_qs_kind_set,&
      71              :                                               qs_kind_type
      72              :    USE qs_neighbor_list_types,          ONLY: get_iterator_info,&
      73              :                                               neighbor_list_iterator_create,&
      74              :                                               neighbor_list_iterator_p_type,&
      75              :                                               neighbor_list_iterator_release,&
      76              :                                               neighbor_list_set_p_type,&
      77              :                                               nl_set_sub_iterator,&
      78              :                                               nl_sub_iterate
      79              :    USE util,                            ONLY: get_limit
      80              :    USE virial_methods,                  ONLY: virial_pair_force
      81              :    USE virial_types,                    ONLY: virial_type
      82              :    USE whittaker,                       ONLY: whittaker_c0a,&
      83              :                                               whittaker_ci
      84              : 
      85              : !$ USE OMP_LIB, ONLY: omp_get_max_threads, omp_get_thread_num
      86              : 
      87              : #include "./base/base_uses.f90"
      88              : 
      89              :    IMPLICIT NONE
      90              : 
      91              :    PRIVATE
      92              : 
      93              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_cneo_methods'
      94              : 
      95              :    PUBLIC :: allocate_rhoz_cneo_internals, calculate_rhoz_cneo, cneo_core_matrices, &
      96              :              init_cneo_potential_internals, Vh_1c_nuc_integrals
      97              : 
      98              : CONTAINS
      99              : 
     100              : ! **************************************************************************************************
     101              : !> \brief ...
     102              : !> \param potential ...
     103              : !> \param nuc_basis ...
     104              : !> \param nuc_soft_basis ...
     105              : !> \param gapw_control ...
     106              : !> \param grid_atom ...
     107              : ! **************************************************************************************************
     108            8 :    SUBROUTINE init_cneo_potential_internals(potential, nuc_basis, nuc_soft_basis, gapw_control, grid_atom)
     109              : 
     110              :       TYPE(cneo_potential_type), POINTER                 :: potential
     111              :       TYPE(gto_basis_set_type), POINTER                  :: nuc_basis, nuc_soft_basis
     112              :       TYPE(gapw_control_type), POINTER                   :: gapw_control
     113              :       TYPE(grid_atom_type), POINTER                      :: grid_atom
     114              : 
     115              :       CHARACTER(len=*), PARAMETER :: routineN = 'init_cneo_potential_internals'
     116              : 
     117              :       INTEGER :: handle, i, icg, ico, ii, ipgf, ipgf1, ipgf2, ir, is1, is2, iset, iset1, iset2, &
     118              :          iso, iso1, iso2, iso_pgf, iso_set, j, k, k1, k2, l, l_iso, l_sub, l_sum, ll, llmax, &
     119              :          lmax12, lmax_expansion, lmax_sphere, lmin12, m, m1, m2, max_iso_not0, max_iso_not0_local, &
     120              :          max_s, max_s_harm, maxl, maxso, n1, n2, nl, nne, npgf2, npgf_sum, npsgf, nr, ns, nset, &
     121              :          nsgf, nsotot, nsox
     122            8 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: cg_n_list
     123            8 :       INTEGER, ALLOCATABLE, DIMENSION(:, :, :)           :: cg_list
     124              :       INTEGER, DIMENSION(0:lmat, 100)                    :: set_index, shell_index
     125            8 :       INTEGER, DIMENSION(:), POINTER                     :: lmax, lmin, n2oindex, npgf, npgf_s, &
     126            8 :                                                             nshell, o2nindex
     127            8 :       INTEGER, DIMENSION(:, :), POINTER                  :: first_sgf, ls
     128            8 :       LOGICAL, ALLOCATABLE, DIMENSION(:, :)              :: done_vgg
     129              :       REAL(KIND=dp)                                      :: c1, c2, gcc_tmp, mass, massinv, &
     130              :                                                             root_zet12, scal, scal1, zet12
     131            8 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: erf_zet12, g1, g2, gg0, int1, int2
     132            8 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: work
     133            8 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: dist
     134            8 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: kin, my_gcc_h, my_gcc_s, oorad2l, ovlp, &
     135            8 :                                                             rad2l, utrans, zet
     136            8 :       REAL(KIND=dp), DIMENSION(:, :, :), POINTER         :: distance, gcc_h, gcc_s, gg, my_CG
     137            8 :       REAL(KIND=dp), DIMENSION(:, :, :, :), POINTER      :: vgg
     138              :       TYPE(atom_basis_type), POINTER                     :: basis
     139              :       TYPE(atom_integrals), POINTER                      :: integrals
     140              :       TYPE(grid_atom_type), POINTER                      :: grid
     141              :       TYPE(harmonics_atom_type), POINTER                 :: harmonics
     142              : 
     143            0 :       CPASSERT(ASSOCIATED(potential))
     144            8 :       CPASSERT(ASSOCIATED(nuc_basis))
     145            8 :       CPASSERT(ASSOCIATED(nuc_soft_basis))
     146              : 
     147            8 :       CALL cite_reference(Chen2025)
     148              : 
     149            8 :       CALL timeset(routineN, handle)
     150              : 
     151              :       CALL get_cneo_potential(potential, my_gcc_h=my_gcc_h, my_gcc_s=my_gcc_s, &
     152              :                               ovlp=ovlp, kin=kin, utrans=utrans, distance=distance, &
     153              :                               harmonics=harmonics, gg=gg, vgg=vgg, n2oindex=n2oindex, &
     154            8 :                               o2nindex=o2nindex, rad2l=rad2l, oorad2l=oorad2l)
     155            8 :       CPASSERT(.NOT. ASSOCIATED(my_gcc_h))
     156            8 :       CPASSERT(.NOT. ASSOCIATED(my_gcc_s))
     157            8 :       CPASSERT(.NOT. ASSOCIATED(ovlp))
     158            8 :       CPASSERT(.NOT. ASSOCIATED(kin))
     159            8 :       CPASSERT(.NOT. ASSOCIATED(utrans))
     160            8 :       CPASSERT(.NOT. ASSOCIATED(distance))
     161            8 :       CPASSERT(.NOT. ASSOCIATED(harmonics))
     162            8 :       CPASSERT(.NOT. ASSOCIATED(gg))
     163            8 :       CPASSERT(.NOT. ASSOCIATED(vgg))
     164            8 :       CPASSERT(.NOT. ASSOCIATED(n2oindex))
     165            8 :       CPASSERT(.NOT. ASSOCIATED(o2nindex))
     166            8 :       CPASSERT(.NOT. ASSOCIATED(rad2l))
     167            8 :       CPASSERT(.NOT. ASSOCIATED(oorad2l))
     168              : 
     169              :       ! ovlp, kin and utrans parts are mostly copied from atom_kind_orbitals::calculate_atomic_orbitals
     170              :       ! and atom_set_basis::set_kind_basis_atomic
     171            8 :       NULLIFY (basis, integrals, grid)
     172         1848 :       ALLOCATE (basis, integrals)
     173            8 :       CALL allocate_grid_atom(grid)
     174            8 :       basis%grid => grid
     175            8 :       NULLIFY (basis%am, basis%cm, basis%as, basis%ns, basis%bf, basis%dbf, basis%ddbf)
     176              :       ! fill in the basis data structures
     177            8 :       basis%basis_type = CGTO_BASIS
     178            8 :       basis%eps_eig = 1.e-12_dp
     179              : 
     180            8 :       NULLIFY (nshell, npgf, lmin, lmax, ls, zet, gcc_h, first_sgf)
     181              :       CALL get_gto_basis_set(nuc_basis, nset=nset, nshell=nshell, npgf=npgf, lmin=lmin, &
     182              :                              lmax=lmax, l=ls, nsgf=nsgf, zet=zet, gcc=gcc_h, first_sgf=first_sgf, &
     183            8 :                              maxl=maxl, maxso=maxso, npgf_sum=npgf_sum)
     184            8 :       NULLIFY (npgf_s, gcc_s)
     185            8 :       CALL get_gto_basis_set(nuc_soft_basis, npgf=npgf_s, gcc=gcc_s)
     186              :       ! There is such a limitation because we rely on atomic code to build S, T and U.
     187              :       ! Usually l=5 is more than enough, suppoting PB6H basis.
     188            8 :       IF (maxl > lmat) &
     189              :          CALL cp_abort(__LOCATION__, "Nuclear basis with angular momentum higher than "// &
     190            0 :                        "atom_types::lmat is not supported yet.")
     191              : 
     192            8 :       set_index = 0
     193            8 :       shell_index = 0
     194           56 :       basis%nprim = 0
     195           56 :       basis%nbas = 0
     196           80 :       DO i = 1, nset
     197          144 :          DO j = lmin(i), MIN(lmax(i), lmat)
     198          144 :             basis%nprim(j) = basis%nprim(j) + npgf(i)
     199              :          END DO
     200          152 :          DO j = 1, nshell(i)
     201           72 :             l = ls(j, i)
     202          144 :             IF (l <= lmat) THEN
     203           72 :                basis%nbas(l) = basis%nbas(l) + 1
     204           72 :                k = basis%nbas(l)
     205           72 :                CPASSERT(k <= 100)
     206           72 :                set_index(l, k) = i
     207           72 :                shell_index(l, k) = j
     208              :             END IF
     209              :          END DO
     210              :       END DO
     211              : 
     212           56 :       nl = MAXVAL(basis%nprim)
     213           56 :       ns = MAXVAL(basis%nbas)
     214           24 :       ALLOCATE (basis%am(nl, 0:lmat))
     215          248 :       basis%am = 0._dp
     216           40 :       ALLOCATE (basis%cm(nl, ns, 0:lmat))
     217         1016 :       basis%cm = 0._dp
     218           56 :       DO l = 0, lmat
     219              :          nl = 0
     220              :          ns = 0
     221          488 :          DO i = 1, nset
     222          480 :             IF (l >= lmin(i) .AND. l <= lmax(i)) THEN
     223          144 :                DO ipgf = 1, npgf(i)
     224          144 :                   basis%am(nl + ipgf, l) = zet(ipgf, i)
     225              :                END DO
     226          144 :                DO ii = 1, nshell(i)
     227          144 :                   IF (ls(ii, i) == l) THEN
     228           72 :                      ns = ns + 1
     229          144 :                      DO ipgf = 1, npgf(i)
     230          144 :                         basis%cm(nl + ipgf, ns, l) = gcc_h(ipgf, ii, i) ! NOTE: not normalized
     231              :                      END DO
     232              :                   END IF
     233              :                END DO
     234           72 :                nl = nl + npgf(i)
     235              :             END IF
     236              :          END DO
     237              :       END DO
     238              : 
     239              :       ! overlap, kinetic and transformation matrices
     240            8 :       CALL atom_int_setup(integrals, basis)
     241              : 
     242              :       ! make the integrals full matrix form
     243           64 :       ALLOCATE (ovlp(nsgf, nsgf), kin(nsgf, nsgf), utrans(nsgf, nsgf))
     244         4424 :       ovlp = 0.0_dp
     245         4424 :       kin = 0.0_dp
     246         4424 :       utrans = 0.0_dp
     247            8 :       CALL get_cneo_potential(potential, mass=mass)
     248            8 :       mass = mass*massunit
     249            8 :       massinv = 1._dp/mass
     250            8 :       nne = 0 ! number of linear-independent spherical basis functions
     251           56 :       DO l = 0, lmat
     252           48 :          ll = 2*l
     253          120 :          DO k2 = 1, integrals%nne(l)
     254          304 :             DO m = 0, ll
     255          184 :                nne = nne + 1
     256          760 :                DO k1 = 1, basis%nbas(l)
     257          504 :                   scal1 = SQRT(integrals%ovlp(k1, k1, l))
     258          504 :                   i = first_sgf(shell_index(l, k1), set_index(l, k1))
     259          688 :                   utrans(i + m, nne) = integrals%utrans(k1, k2, l)*scal1
     260              :                END DO
     261              :             END DO
     262              :          END DO
     263          128 :          DO k1 = 1, basis%nbas(l)
     264           72 :             scal1 = 1._dp/SQRT(integrals%ovlp(k1, k1, l))
     265           72 :             i = first_sgf(shell_index(l, k1), set_index(l, k1))
     266          352 :             DO k2 = 1, basis%nbas(l)
     267          232 :                scal = scal1/SQRT(integrals%ovlp(k2, k2, l))
     268          232 :                j = first_sgf(shell_index(l, k2), set_index(l, k2))
     269          808 :                DO m = 0, ll
     270              :                   ! normalize the integrals
     271          504 :                   ovlp(i + m, j + m) = integrals%ovlp(k1, k2, l)*scal
     272          736 :                   kin(i + m, j + m) = integrals%kin(k1, k2, l)*scal*massinv
     273              :                END DO
     274              :             END DO
     275              :          END DO
     276              :       END DO
     277              : 
     278            8 :       nsotot = maxso*nset
     279           48 :       ALLOCATE (my_gcc_h(nsotot, nsgf), my_gcc_s(nsotot, nsgf))
     280        15096 :       my_gcc_h = 0.0_dp
     281        15096 :       my_gcc_s = 0.0_dp
     282              :       ! create gcc that really 3D-normalize the basis functions
     283           32 :       DO l = 0, MIN(maxl, lmat)
     284           24 :          ns = 0
     285           24 :          m = 0
     286           24 :          ll = 2*l
     287           24 :          k = nsoset(l - 1) + 1
     288          248 :          DO i = 1, nset
     289          216 :             IF (l >= lmin(i) .AND. l <= lmax(i)) THEN
     290           72 :                nsox = nsoset(lmax(i))
     291          144 :                DO ii = 1, nshell(i)
     292          144 :                   IF (ls(ii, i) == l) THEN
     293           72 :                      ns = ns + 1
     294           72 :                      k1 = first_sgf(shell_index(l, ns), set_index(l, ns))
     295           72 :                      scal = 1._dp/SQRT(integrals%ovlp(ns, ns, l))
     296          144 :                      DO ipgf = 1, npgf(i)
     297           72 :                         gcc_tmp = gcc_h(ipgf, ii, i)*scal
     298           72 :                         k2 = (ipgf - 1)*nsox + m
     299          328 :                         DO j = 0, ll
     300          256 :                            my_gcc_h(k + k2 + j, k1 + j) = gcc_tmp
     301              :                         END DO
     302              :                      END DO
     303           86 :                      DO ipgf = 1, npgf_s(i)
     304           14 :                         gcc_tmp = gcc_s(ipgf, ii, i)*scal
     305           14 :                         k2 = (ipgf - 1)*nsox + m
     306          112 :                         DO j = 0, ll
     307           40 :                            my_gcc_s(k + k2 + j, k1 + j) = gcc_tmp
     308              :                         END DO
     309              :                      END DO
     310              :                   END IF
     311              :                END DO
     312              :             END IF
     313          240 :             m = m + maxso
     314              :          END DO
     315              :       END DO
     316              : 
     317            8 :       CALL atom_int_release(integrals)
     318              :       CALL set_cneo_potential(potential, nsgf=nsgf, nne=nne, nsotot=nsotot, &
     319              :                               my_gcc_h=my_gcc_h, my_gcc_s=my_gcc_s, &
     320            8 :                               ovlp=ovlp, kin=kin, utrans=utrans)
     321            8 :       CALL release_atom_basis(basis)
     322            8 :       DEALLOCATE (basis, integrals)
     323              : 
     324              :       ! initialize my_CG
     325            8 :       lmax_sphere = gapw_control%lmax_sphere
     326              :       ! make sure llmax is at least 1 such that distance matrices can be generated
     327            8 :       llmax = MAX(1, MIN(lmax_sphere, 2*maxl))
     328            8 :       max_s_harm = nsoset(llmax)
     329            8 :       max_s = nsoset(maxl)
     330            8 :       NULLIFY (my_CG)
     331            8 :       CALL reallocate(my_CG, 1, max_s, 1, max_s, 1, max_s_harm)
     332            8 :       CALL create_my_CG_cneo(my_CG, MAX(llmax, 2*maxl, 1), maxl, llmax)
     333              : 
     334              :       ! initialize harmonics
     335            8 :       CALL allocate_harmonics_atom(harmonics)
     336            8 :       CALL create_harmonics_atom_cneo(harmonics, my_CG, llmax, max_s, max_s_harm)
     337            8 :       DEALLOCATE (my_CG)
     338            8 :       CALL get_maxl_CG_cneo(harmonics, nuc_basis, llmax, max_s_harm)
     339              : 
     340            8 :       CALL set_cneo_potential(potential, harmonics=harmonics)
     341              : 
     342              :       ! initialize my own rad2l and oorad2l
     343              :       ! copied from qs_grid_atom::create_grid_atom
     344            8 :       nr = grid_atom%nr
     345            8 :       NULLIFY (rad2l, oorad2l)
     346            8 :       CALL reallocate(rad2l, 1, nr, 0, llmax + 1)
     347            8 :       CALL reallocate(oorad2l, 1, nr, 0, llmax + 1)
     348          408 :       rad2l(:, 0) = 1._dp
     349          408 :       oorad2l(:, 0) = 1._dp
     350           48 :       DO l = 1, llmax + 1
     351         4040 :          rad2l(:, l) = rad2l(:, l - 1)*grid_atom%rad(:)
     352         4048 :          oorad2l(:, l) = oorad2l(:, l - 1)/grid_atom%rad(:)
     353              :       END DO
     354            8 :       CALL set_cneo_potential(potential, rad2l=rad2l, oorad2l=oorad2l)
     355              :       ! still need to bump lmax in grid_atom as qs_rho0_types::calculate_g0 uses it
     356            8 :       IF (SIZE(rad2l, 2) > SIZE(grid_atom%rad2l, 2)) THEN
     357            2 :          CPASSERT(SIZE(rad2l, 1) == SIZE(grid_atom%rad2l, 1))
     358            2 :          DEALLOCATE (grid_atom%rad2l)
     359            2 :          NULLIFY (grid_atom%rad2l)
     360            2 :          CALL reallocate(grid_atom%rad2l, 1, nr, 0, llmax + 1)
     361         1226 :          grid_atom%rad2l = rad2l
     362              :       END IF
     363            8 :       IF (SIZE(oorad2l, 2) > SIZE(grid_atom%oorad2l, 2)) THEN
     364            2 :          CPASSERT(SIZE(oorad2l, 1) == SIZE(grid_atom%oorad2l, 1))
     365            2 :          DEALLOCATE (grid_atom%oorad2l)
     366            2 :          NULLIFY (grid_atom%oorad2l)
     367            2 :          CALL reallocate(grid_atom%oorad2l, 1, nr, 0, llmax + 1)
     368         1226 :          grid_atom%oorad2l = oorad2l
     369              :       END IF
     370              : 
     371              :       ! distance matrices
     372           72 :       ALLOCATE (distance(nsgf, nsgf, 3), dist(nsotot, nsotot, 3))
     373        13280 :       distance = 0.0_dp
     374       159440 :       dist = 0.0_dp
     375              :       ! initialize gg and vgg
     376              :       ! mostly copied from qs_rho_atom_methods::calculate_rho_atom
     377            8 :       max_iso_not0 = harmonics%max_iso_not0
     378            8 :       lmax_expansion = indso(1, max_iso_not0)
     379            8 :       my_CG => harmonics%my_CG
     380           72 :       ALLOCATE (g1(nr), g2(nr), gg0(nr), gg(nr, 0:2*maxl, npgf_sum*(npgf_sum + 1)/2))
     381           56 :       ALLOCATE (erf_zet12(nr), vgg(nr, 0:2*maxl, 0:indso(1, max_iso_not0), npgf_sum*(npgf_sum + 1)/2))
     382           32 :       ALLOCATE (done_vgg(0:2*maxl, 0:indso(1, max_iso_not0)))
     383           24 :       ALLOCATE (int1(nr), int2(nr))
     384           48 :       ALLOCATE (cg_list(2, nsoset(maxl)**2, max_s_harm), cg_n_list(max_s_harm))
     385              : 
     386            8 :       j = 0
     387            8 :       m1 = 0
     388           80 :       DO iset1 = 1, nset
     389           72 :          n1 = nsoset(lmax(iset1))
     390           72 :          m2 = 0
     391          432 :          DO iset2 = 1, iset1
     392          360 :             n2 = nsoset(lmax(iset2))
     393              : 
     394              :             CALL get_none0_cg_list(my_CG, lmin(iset1), lmax(iset1), lmin(iset2), lmax(iset2), &
     395          360 :                                    max_s_harm, lmax_expansion, cg_list, cg_n_list, max_iso_not0_local)
     396          360 :             CPASSERT(max_iso_not0_local <= max_iso_not0)
     397              : 
     398          720 :             DO ipgf1 = 1, npgf(iset1)
     399        18360 :                g1(1:nr) = EXP(-zet(ipgf1, iset1)*grid_atom%rad2(1:nr))
     400              : 
     401          360 :                IF (iset2 == iset1) THEN
     402              :                   npgf2 = ipgf1
     403              :                ELSE
     404          288 :                   npgf2 = npgf(iset2)
     405              :                END IF
     406         1080 :                DO ipgf2 = 1, npgf2
     407          360 :                   zet12 = zet(ipgf1, iset1) + zet(ipgf2, iset2)
     408              : 
     409              :                   ! distance part
     410              :                   ! -1 -> y -> 2, 0 -> z -> 3, 1 -> x -> 1
     411         1440 :                   DO m = -1, 1
     412         1080 :                      k = m + 3
     413         1080 :                      IF (m == 1) k = 1
     414         1080 :                      iso = indso_inv(1, m)
     415         2256 :                      DO icg = 1, cg_n_list(iso)
     416          816 :                         is1 = cg_list(1, icg, iso)
     417          816 :                         is2 = cg_list(2, icg, iso)
     418              : 
     419          816 :                         iso1 = is1 + n1*(ipgf1 - 1) + m1
     420          816 :                         iso2 = is2 + n2*(ipgf2 - 1) + m2
     421              : 
     422          816 :                         l = indso(1, is1) + indso(1, is2)
     423              :                         dist(iso1, iso2, k) = dist(iso1, iso2, k) + my_CG(is1, is2, iso)* &
     424              :                                               pi*dfac(l + 2)/ &
     425          816 :                                               ((2.0_dp*zet12)**((l + 3)/2)*SQRT(3.0_dp*zet12))
     426         1896 :                         dist(iso2, iso1, k) = dist(iso1, iso2, k) ! symmetric
     427              :                      END DO !icg
     428              :                   END DO
     429              : 
     430              :                   ! gg and vgg part
     431          360 :                   j = j + 1
     432        18360 :                   g2(1:nr) = EXP(-zet(ipgf2, iset2)*grid_atom%rad2(1:nr))
     433          360 :                   lmin12 = lmin(iset1) + lmin(iset2)
     434          360 :                   lmax12 = lmax(iset1) + lmax(iset2)
     435              : 
     436          360 :                   root_zet12 = SQRT(zet12)
     437        18360 :                   DO ir = 1, nr
     438        18360 :                      erf_zet12(ir) = erf(root_zet12*grid_atom%rad(ir))
     439              :                   END DO
     440              : 
     441        92160 :                   gg(:, :, j) = 0.0_dp
     442       461160 :                   vgg(:, :, :, j) = 0.0_dp
     443        11160 :                   done_vgg = .FALSE.
     444              :                   ! reduce the number of terms in the expansion local densities
     445          720 :                   IF (lmin12 <= lmax_expansion) THEN
     446          360 :                      IF (lmin12 == 0) THEN
     447         4080 :                         gg(1:nr, lmin12, j) = g1(1:nr)*g2(1:nr)
     448         4080 :                         gg0(1:nr) = gg(1:nr, lmin12, j)
     449              :                      ELSE
     450        14280 :                         gg0(1:nr) = g1(1:nr)*g2(1:nr)
     451        28280 :                         gg(1:nr, lmin12, j) = rad2l(1:nr, lmin12)*g1(1:nr)*g2(1:nr)
     452              :                      END IF
     453              : 
     454              :                      ! reduce the number of terms in the expansion local densities
     455          360 :                      IF (lmax12 > lmax_expansion) lmax12 = lmax_expansion
     456              : 
     457          360 :                      DO l = lmin12 + 1, lmax12
     458          360 :                         gg(1:nr, l, j) = grid_atom%rad(1:nr)*gg(1:nr, l - 1, j)
     459              :                      END DO
     460              : 
     461          360 :                      c2 = SQRT(pi*pi*pi/(zet12*zet12*zet12))
     462              : 
     463         3200 :                      DO iso = 1, max_iso_not0_local
     464         2840 :                         l_iso = indso(1, iso)
     465         2840 :                         c1 = fourpi/(2._dp*REAL(l_iso, dp) + 1._dp)
     466         7704 :                         DO icg = 1, cg_n_list(iso)
     467         4504 :                            iso1 = cg_list(1, icg, iso)
     468         4504 :                            iso2 = cg_list(2, icg, iso)
     469              : 
     470         4504 :                            l = indso(1, iso1) + indso(1, iso2)
     471         4504 :                            CPASSERT(l <= lmax_expansion)
     472         4504 :                            IF (done_vgg(l, l_iso)) CYCLE
     473          504 :                            L_sum = l + l_iso
     474          504 :                            L_sub = l - l_iso
     475              : 
     476          504 :                            IF (l_sum == 0) THEN
     477         8080 :                               vgg(1:nr, l, l_iso, j) = erf_zet12(1:nr)*oorad2l(1:nr, 1)*c2
     478              :                            ELSE
     479          424 :                               CALL whittaker_c0a(int1, grid_atom%rad, gg0, erf_zet12, zet12, l, l_iso, nr)
     480          424 :                               CALL whittaker_ci(int2, grid_atom%rad, gg0, zet12, L_sub, nr)
     481              : 
     482        21624 :                               DO ir = 1, nr
     483        21200 :                                  int2(ir) = rad2l(ir, l_iso)*int2(ir)
     484        21624 :                                  vgg(ir, l, l_iso, j) = c1*(int1(ir) + int2(ir))
     485              :                               END DO
     486              :                            END IF
     487         7344 :                            done_vgg(l, l_iso) = .TRUE.
     488              :                         END DO
     489              :                      END DO
     490              :                   END IF ! lmax_expansion
     491              : 
     492              :                END DO ! ipgf2
     493              :             END DO ! ipgf1
     494          792 :             m2 = m2 + maxso
     495              :          END DO ! iset2
     496           80 :          m1 = m1 + maxso
     497              :       END DO ! iset1
     498              : 
     499            8 :       DEALLOCATE (g1, g2, gg0, erf_zet12, int1, int2, done_vgg)
     500            8 :       DEALLOCATE (cg_list, cg_n_list)
     501              : 
     502           24 :       ALLOCATE (work(nsotot, nsgf))
     503           32 :       DO k = 1, 3
     504              :          CALL dgemm("N", "N", nsotot, nsgf, nsotot, 1.0_dp, dist(:, :, k), nsotot, my_gcc_h, &
     505           24 :                     nsotot, 0.0_dp, work, nsotot)
     506              :          CALL dgemm("T", "N", nsgf, nsgf, nsotot, 1.0_dp, my_gcc_h, nsotot, work, &
     507           32 :                     nsotot, 0.0_dp, distance(:, :, k), nsgf)
     508              :       END DO
     509            8 :       DEALLOCATE (work, dist)
     510            8 :       CALL set_cneo_potential(potential, distance=distance, gg=gg, vgg=vgg)
     511              : 
     512              :       ! Index transformation OLD-NEW
     513              :       ! copied from paw_proj_set_types::build_projector
     514           24 :       ALLOCATE (o2nindex(nsotot))
     515           16 :       ALLOCATE (n2oindex(nsotot))
     516          656 :       o2nindex = 0
     517          656 :       n2oindex = 0
     518              :       ico = 1
     519           80 :       DO iset = 1, nset
     520           72 :          iso_set = (iset - 1)*maxso + 1
     521           72 :          nsox = nsoset(lmax(iset))
     522          152 :          DO ipgf = 1, npgf(iset)
     523           72 :             iso_pgf = iso_set + (ipgf - 1)*nsox
     524           72 :             iso = iso_pgf + nsoset(lmin(iset) - 1)
     525          216 :             DO l = lmin(iset), lmax(iset)
     526          328 :                DO k = 1, nso(l)
     527          184 :                   n2oindex(ico) = iso
     528          184 :                   o2nindex(iso) = ico
     529          184 :                   iso = iso + 1
     530          256 :                   ico = ico + 1
     531              :                END DO
     532              :             END DO
     533              :          END DO
     534              :       END DO
     535            8 :       npsgf = ico - 1
     536            8 :       CALL set_cneo_potential(potential, npsgf=npsgf, n2oindex=n2oindex, o2nindex=o2nindex)
     537              : 
     538            8 :       CALL timestop(handle)
     539              : 
     540           32 :    END SUBROUTINE init_cneo_potential_internals
     541              : 
     542              : ! **************************************************************************************************
     543              : !> \brief ...
     544              : !> \param rhoz_cneo_set ...
     545              : !> \param atomic_kind_set ...
     546              : !> \param qs_kind_set ...
     547              : !> \param qs_env ...
     548              : ! **************************************************************************************************
     549           16 :    SUBROUTINE allocate_rhoz_cneo_internals(rhoz_cneo_set, atomic_kind_set, &
     550              :                                            qs_kind_set, qs_env)
     551              : 
     552              :       TYPE(rhoz_cneo_type), DIMENSION(:), POINTER        :: rhoz_cneo_set
     553              :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
     554              :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     555              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     556              : 
     557              :       CHARACTER(len=*), PARAMETER :: routineN = 'allocate_rhoz_cneo_internals'
     558              : 
     559              :       INTEGER                                            :: bo(2), handle, iat, iatom, ikind, &
     560              :                                                             max_iso_not0, mepos, nat, natom, &
     561              :                                                             npsgf, nr, nsgf, nsotot, num_pe
     562            8 :       INTEGER, DIMENSION(:), POINTER                     :: atom_list
     563              :       LOGICAL                                            :: paw_atom
     564              :       TYPE(cneo_potential_type), POINTER                 :: cneo_potential
     565              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     566              : 
     567            8 :       CALL timeset(routineN, handle)
     568              : 
     569            8 :       CALL get_atomic_kind_set(atomic_kind_set, natom=natom)
     570              : 
     571            8 :       CALL allocate_rhoz_cneo_set(rhoz_cneo_set, natom)
     572              : 
     573            8 :       NULLIFY (para_env)
     574            8 :       CALL get_qs_env(qs_env, para_env=para_env)
     575              : 
     576           22 :       DO ikind = 1, SIZE(atomic_kind_set)
     577              : 
     578           14 :          NULLIFY (cneo_potential)
     579              :          CALL get_qs_kind(qs_kind_set(ikind), &
     580              :                           ngrid_rad=nr, &
     581              :                           paw_atom=paw_atom, &
     582           14 :                           cneo_potential=cneo_potential)
     583              : 
     584           22 :          IF (ASSOCIATED(cneo_potential)) THEN
     585            8 :             CPASSERT(paw_atom)
     586              : 
     587            8 :             NULLIFY (atom_list)
     588            8 :             CALL get_atomic_kind(atomic_kind_set(ikind), atom_list=atom_list, natom=nat)
     589              : 
     590            8 :             nsgf = cneo_potential%nsgf
     591            8 :             npsgf = cneo_potential%npsgf
     592            8 :             nsotot = cneo_potential%nsotot
     593              : 
     594           22 :             DO iat = 1, nat
     595           14 :                iatom = atom_list(iat)
     596              : 
     597              :                ! density matrices, core and soft vmat will be broadcast to all processes
     598              :                ALLOCATE (rhoz_cneo_set(iatom)%pmat(1:nsgf, 1:nsgf), &
     599              :                          rhoz_cneo_set(iatom)%cpc_h(1:npsgf, 1:npsgf), &
     600              :                          rhoz_cneo_set(iatom)%cpc_s(1:npsgf, 1:npsgf), &
     601              :                          rhoz_cneo_set(iatom)%core(1:nsgf, 1:nsgf), &
     602          224 :                          rhoz_cneo_set(iatom)%vmat(1:nsgf, 1:nsgf))
     603         7742 :                rhoz_cneo_set(iatom)%pmat = 0.0_dp
     604         7742 :                rhoz_cneo_set(iatom)%cpc_h = 0.0_dp
     605         7742 :                rhoz_cneo_set(iatom)%cpc_s = 0.0_dp
     606         7742 :                rhoz_cneo_set(iatom)%core = 0.0_dp
     607         7750 :                rhoz_cneo_set(iatom)%vmat = 0.0_dp
     608              :             END DO
     609              : 
     610            8 :             max_iso_not0 = cneo_potential%harmonics%max_iso_not0
     611            8 :             num_pe = para_env%num_pe
     612            8 :             mepos = para_env%mepos
     613            8 :             bo = get_limit(nat, num_pe, mepos)
     614           15 :             DO iat = bo(1), bo(2)
     615            7 :                iatom = atom_list(iat)
     616              : 
     617              :                ALLOCATE (rhoz_cneo_set(iatom)%fmat(1:nsgf, 1:nsgf), &
     618           49 :                          rhoz_cneo_set(iatom)%wfn(1:nsgf, 1:nsgf))
     619         3871 :                rhoz_cneo_set(iatom)%fmat = 0.0_dp
     620         3871 :                rhoz_cneo_set(iatom)%wfn = 0.0_dp
     621              : 
     622              :                ALLOCATE (rhoz_cneo_set(iatom)%rho_rad_h(1:nr, 1:max_iso_not0), &
     623              :                          rhoz_cneo_set(iatom)%rho_rad_s(1:nr, 1:max_iso_not0), &
     624              :                          rhoz_cneo_set(iatom)%vrho_rad_h(1:nr, 1:max_iso_not0), &
     625           91 :                          rhoz_cneo_set(iatom)%vrho_rad_s(1:nr, 1:max_iso_not0))
     626         8932 :                rhoz_cneo_set(iatom)%rho_rad_h = 0.0_dp
     627         8932 :                rhoz_cneo_set(iatom)%rho_rad_s = 0.0_dp
     628         8932 :                rhoz_cneo_set(iatom)%vrho_rad_h = 0.0_dp
     629         8932 :                rhoz_cneo_set(iatom)%vrho_rad_s = 0.0_dp
     630              : 
     631            7 :                NULLIFY (rhoz_cneo_set(iatom)%ga_Vlocal_gb_h)
     632            7 :                CALL reallocate(rhoz_cneo_set(iatom)%ga_Vlocal_gb_h, 1, nsotot, 1, nsotot)
     633        46501 :                rhoz_cneo_set(iatom)%ga_Vlocal_gb_h = 0.0_dp
     634            7 :                NULLIFY (rhoz_cneo_set(iatom)%ga_Vlocal_gb_s)
     635            7 :                CALL reallocate(rhoz_cneo_set(iatom)%ga_Vlocal_gb_s, 1, nsotot, 1, nsotot)
     636        46509 :                rhoz_cneo_set(iatom)%ga_Vlocal_gb_s = 0.0_dp
     637              :             END DO ! iat
     638              :          END IF
     639              : 
     640              :       END DO
     641              : 
     642            8 :       CALL timestop(handle)
     643              : 
     644            8 :    END SUBROUTINE allocate_rhoz_cneo_internals
     645              : 
     646              : ! **************************************************************************************************
     647              : !> \brief ...
     648              : !> \param qs_env ...
     649              : !> \param calculate_forces ...
     650              : !> \param nder ...
     651              : ! **************************************************************************************************
     652        16625 :    SUBROUTINE cneo_core_matrices(qs_env, calculate_forces, nder)
     653              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     654              :       LOGICAL, INTENT(IN)                                :: calculate_forces
     655              :       INTEGER, INTENT(IN)                                :: nder
     656              : 
     657              :       LOGICAL                                            :: use_virial
     658        16625 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
     659              :       TYPE(distribution_1d_type), POINTER                :: distribution_1d
     660              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     661              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
     662        16625 :          POINTER                                         :: sab_cneo
     663        16625 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     664        16625 :       TYPE(qs_force_type), DIMENSION(:), POINTER         :: force
     665        16625 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     666        16625 :       TYPE(rhoz_cneo_type), DIMENSION(:), POINTER        :: rhoz_cneo_set
     667              :       TYPE(virial_type), POINTER                         :: virial
     668              : 
     669        16625 :       NULLIFY (rhoz_cneo_set)
     670        16625 :       CALL get_qs_env(qs_env=qs_env, rhoz_cneo_set=rhoz_cneo_set)
     671              : 
     672        16625 :       IF (ASSOCIATED(rhoz_cneo_set)) THEN
     673           14 :          NULLIFY (force, virial)
     674              :          ! force
     675           14 :          IF (calculate_forces) CALL get_qs_env(qs_env=qs_env, force=force)
     676              :          ! virial
     677           14 :          CALL get_qs_env(qs_env=qs_env, virial=virial)
     678           14 :          use_virial = virial%pv_availability .AND. (.NOT. virial%pv_numer)
     679              : 
     680           14 :          NULLIFY (qs_kind_set, atomic_kind_set, particle_set, distribution_1d, para_env, sab_cneo)
     681              :          CALL get_qs_env(qs_env=qs_env, qs_kind_set=qs_kind_set, atomic_kind_set=atomic_kind_set, &
     682              :                          particle_set=particle_set, local_particles=distribution_1d, &
     683           14 :                          para_env=para_env, sab_cneo=sab_cneo)
     684              :          CALL build_core_cneo(rhoz_cneo_set, force, virial, calculate_forces, use_virial, nder, &
     685              :                               qs_kind_set, atomic_kind_set, particle_set, distribution_1d, &
     686           14 :                               sab_cneo, para_env)
     687              :       END IF
     688              : 
     689        16625 :    END SUBROUTINE cneo_core_matrices
     690              : 
     691              : ! **************************************************************************************************
     692              : !> \brief ...
     693              : !> \param rhoz_cneo_set ...
     694              : !> \param force ...
     695              : !> \param virial ...
     696              : !> \param calculate_forces ...
     697              : !> \param use_virial ...
     698              : !> \param nder ...
     699              : !> \param qs_kind_set ...
     700              : !> \param atomic_kind_set ...
     701              : !> \param particle_set ...
     702              : !> \param distribution_1d ...
     703              : !> \param sab_cneo ...
     704              : !> \param para_env ...
     705              : ! **************************************************************************************************
     706           14 :    SUBROUTINE build_core_cneo(rhoz_cneo_set, force, virial, calculate_forces, use_virial, nder, &
     707              :                               qs_kind_set, atomic_kind_set, particle_set, distribution_1d, &
     708              :                               sab_cneo, para_env)
     709              :       TYPE(rhoz_cneo_type), DIMENSION(:), POINTER        :: rhoz_cneo_set
     710              :       TYPE(qs_force_type), DIMENSION(:), POINTER         :: force
     711              :       TYPE(virial_type), POINTER                         :: virial
     712              :       LOGICAL, INTENT(IN)                                :: calculate_forces, use_virial
     713              :       INTEGER, INTENT(IN)                                :: nder
     714              :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     715              :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
     716              :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     717              :       TYPE(distribution_1d_type), POINTER                :: distribution_1d
     718              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
     719              :          POINTER                                         :: sab_cneo
     720              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     721              : 
     722              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'build_core_cneo'
     723              : 
     724              :       INTEGER :: atom_a, handle, iat, iatom, ikind, iset, jatom, jkind, jset, ldai, ldsab, maxco, &
     725              :          maxl, maxnset, maxsgf, mepos, na_plus, nat, natom, nb_plus, ncoa, ncob, nij, nkind, nset, &
     726              :          nthread, sgfa, sgfb
     727           14 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: atom_of_kind, kind_of
     728           14 :       INTEGER, DIMENSION(:), POINTER                     :: atom_list, lmax, lmin, npgf, nsgf
     729           14 :       INTEGER, DIMENSION(:, :), POINTER                  :: first_sgf
     730              :       REAL(KIND=dp)                                      :: alpha_c, core_charge, core_radius, dab, &
     731              :                                                             f0, rab2, zeta_i, zeta_j
     732           14 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: ff
     733           14 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: habd, work
     734           14 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: hab, pab, verf, vnuc
     735              :       REAL(KIND=dp), DIMENSION(3)                        :: force_a, force_b, force_i, rab
     736              :       REAL(KIND=dp), DIMENSION(3, 3)                     :: pv_thread
     737              :       TYPE(neighbor_list_iterator_p_type), &
     738           14 :          DIMENSION(:), POINTER                           :: ap_iterator
     739              :       TYPE(gto_basis_set_type), POINTER                  :: basis_set
     740              :       TYPE(cneo_potential_type), POINTER                 :: cneo_potential, cneo_tmp
     741           14 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: core, pmat, rpgf, sphi, zet
     742           14 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: set_radius
     743           28 :       REAL(KIND=dp), DIMENSION(3, SIZE(particle_set))    :: force_thread
     744              : 
     745           28 :       IF (calculate_forces) THEN
     746            6 :          CALL timeset(routineN//"_forces", handle)
     747              :       ELSE
     748            8 :          CALL timeset(routineN, handle)
     749              :       END IF
     750              : 
     751           14 :       nkind = SIZE(atomic_kind_set)
     752           14 :       natom = SIZE(particle_set)
     753              : 
     754          166 :       force_thread = 0.0_dp
     755           14 :       pv_thread = 0.0_dp
     756              : 
     757              :       ! re-initialize core matrices to zero, as later will use para_env%sum to broadcast
     758           40 :       DO ikind = 1, nkind
     759           26 :          NULLIFY (cneo_potential)
     760           26 :          CALL get_qs_kind(qs_kind_set(ikind), cneo_potential=cneo_potential)
     761              : 
     762           40 :          IF (ASSOCIATED(cneo_potential)) THEN
     763           14 :             NULLIFY (atom_list)
     764           14 :             CALL get_atomic_kind(atomic_kind_set(ikind), atom_list=atom_list, natom=nat)
     765           40 :             DO iat = 1, nat
     766           26 :                iatom = atom_list(iat)
     767        14392 :                rhoz_cneo_set(iatom)%core = 0.0_dp
     768              :             END DO
     769              :          END IF
     770              :       END DO
     771              : 
     772              :       CALL get_qs_kind_set(qs_kind_set, basis_type="NUC", &
     773           14 :                            maxco=maxco, maxlgto=maxl, maxsgf=maxsgf, maxnset=maxnset)
     774           14 :       CALL init_orbital_pointers(maxl + nder + 1)
     775           14 :       ldsab = MAX(maxco, maxsgf)
     776           14 :       ldai = ncoset(maxl + nder + 1)
     777              : 
     778              :       nthread = 1
     779           14 : !$    nthread = omp_get_max_threads()
     780              : 
     781           14 :       CALL neighbor_list_iterator_create(ap_iterator, sab_cneo, search=.TRUE., nthread=nthread)
     782              : 
     783              : !$OMP PARALLEL &
     784              : !$OMP DEFAULT (NONE) &
     785              : !$OMP SHARED  (rhoz_cneo_set, ap_iterator, distribution_1d, calculate_forces, use_virial, &
     786              : !$OMP          qs_kind_set, nthread, ncoset, nkind, iat, ldsab, maxnset, ldai, nder, maxl, &
     787              : !$OMP          maxco, para_env) &
     788              : !$OMP PRIVATE (ikind, jkind, iatom, jatom, basis_set, first_sgf, lmax, lmin, npgf, nset, &
     789              : !$OMP          nsgf, rpgf, sphi, zet, set_radius, zeta_i, zeta_j, alpha_c, core_charge, &
     790              : !$OMP          core_radius, rab, rab2, dab, core, pmat, iset, ncoa, sgfa, jset, ncob, sgfb, &
     791              : !$OMP          work, pab, hab, na_plus, nb_plus, verf, vnuc, force_a, force_b, force_i, &
     792              : !$OMP          mepos, habd, f0, nij, ff, cneo_potential, cneo_tmp) &
     793           14 : !$OMP REDUCTION (+ : pv_thread, force_thread )
     794              : 
     795              :       mepos = 0
     796              : !$    mepos = omp_get_thread_num()
     797              : 
     798              :       ALLOCATE (hab(ldsab, ldsab, maxnset*(maxnset + 1)/2), work(ldsab, ldsab))
     799              :       ALLOCATE (verf(ldai, ldai, 2*maxl + nder + 1), vnuc(ldai, ldai, 2*maxl + nder + 1), ff(0:2*maxl + nder))
     800              :       IF (calculate_forces) THEN
     801              :          ALLOCATE (pab(maxco, maxco, maxnset*(maxnset + 1)/2))
     802              :       END IF
     803              : 
     804              :       DO ikind = 1, nkind
     805              :          NULLIFY (cneo_potential)
     806              :          CALL get_qs_kind(qs_kind_set(ikind), basis_set=basis_set, basis_type="NUC", &
     807              :                           cneo_potential=cneo_potential, zeff=zeta_i)
     808              :          IF (ASSOCIATED(cneo_potential)) THEN
     809              :             CPASSERT(ASSOCIATED(basis_set))
     810              :             first_sgf => basis_set%first_sgf
     811              :             lmax => basis_set%lmax
     812              :             lmin => basis_set%lmin
     813              :             npgf => basis_set%npgf
     814              :             nset = basis_set%nset
     815              :             nsgf => basis_set%nsgf_set
     816              :             rpgf => basis_set%pgf_radius
     817              :             set_radius => basis_set%set_radius
     818              :             sphi => basis_set%sphi
     819              :             zet => basis_set%zet
     820              : 
     821              : !$OMP DO SCHEDULE(GUIDED)
     822              :             DO iat = 1, distribution_1d%n_el(ikind)
     823              :                iatom = distribution_1d%list(ikind)%array(iat)
     824              :                core => rhoz_cneo_set(iatom)%core
     825              :                CPASSERT(ASSOCIATED(core))
     826              :                core = cneo_potential%kin ! copy kinetic matrix to core
     827              :                IF (calculate_forces) THEN
     828              :                   CPASSERT(rhoz_cneo_set(iatom)%ready)
     829              :                   pmat => rhoz_cneo_set(iatom)%pmat
     830              :                   CPASSERT(ASSOCIATED(pmat))
     831              :                   ! *** Decontract density matrix ***
     832              :                   DO iset = 1, nset
     833              :                      ncoa = npgf(iset)*ncoset(lmax(iset))
     834              :                      sgfa = first_sgf(1, iset)
     835              :                      DO jset = 1, iset
     836              :                         ncob = npgf(jset)*ncoset(lmax(jset))
     837              :                         sgfb = first_sgf(1, jset)
     838              :                         nij = jset + (iset - 1)*iset/2
     839              :                         work(1:ncoa, 1:nsgf(jset)) = MATMUL(sphi(1:ncoa, sgfa:sgfa + nsgf(iset) - 1), &
     840              :                                                             pmat(sgfa:sgfa + nsgf(iset) - 1, sgfb:sgfb + nsgf(jset) - 1))
     841              :                         pab(1:ncoa, 1:ncob, nij) = MATMUL(work(1:ncoa, 1:nsgf(jset)), &
     842              :                                                           TRANSPOSE(sphi(1:ncob, sgfb:sgfb + nsgf(jset) - 1)))
     843              :                      END DO
     844              :                   END DO
     845              :                END IF
     846              : 
     847              :                hab = 0._dp
     848              :                DO jkind = 1, nkind
     849              :                   NULLIFY (cneo_tmp)
     850              :                   CALL get_qs_kind(qs_kind_set(jkind), cneo_potential=cneo_tmp)
     851              :                   IF (.NOT. ASSOCIATED(cneo_tmp)) THEN
     852              :                      CALL get_qs_kind(qs_kind_set(jkind), &
     853              :                                       alpha_core_charge=alpha_c, zeff=zeta_j, &
     854              :                                       ccore_charge=core_charge, core_charge_radius=core_radius)
     855              :                      CALL nl_set_sub_iterator(ap_iterator, ikind, jkind, iatom, mepos=mepos)
     856              : 
     857              :                      DO WHILE (nl_sub_iterate(ap_iterator, mepos=mepos) == 0)
     858              :                         CALL get_iterator_info(ap_iterator, jatom=jatom, r=rab, mepos=mepos)
     859              :                         rab2 = SUM(rab*rab)
     860              :                         dab = SQRT(rab2)
     861              :                         IF (MAXVAL(set_radius(:)) + core_radius < dab) CYCLE
     862              :                         DO iset = 1, nset
     863              :                            IF (set_radius(iset) + core_radius < dab) CYCLE
     864              :                            ncoa = npgf(iset)*ncoset(lmax(iset))
     865              :                            sgfa = first_sgf(1, iset)
     866              :                            DO jset = 1, iset ! symmetric
     867              :                               IF (set_radius(jset) + core_radius < dab) CYCLE
     868              :                               ncob = npgf(jset)*ncoset(lmax(jset))
     869              :                               sgfb = first_sgf(1, jset)
     870              :                               nij = jset + (iset - 1)*iset/2
     871              :                               IF (calculate_forces) THEN
     872              :                                  IF (jset == iset) THEN
     873              :                                     f0 = -zeta_i
     874              :                                  ELSE
     875              :                                     f0 = -2.0_dp*zeta_i
     876              :                                  END IF
     877              :                                  na_plus = npgf(iset)*ncoset(lmax(iset) + nder)
     878              :                                  nb_plus = npgf(jset)*ncoset(lmax(jset))
     879              :                                  ALLOCATE (habd(na_plus, nb_plus))
     880              :                                  habd = 0._dp
     881              :                                  CALL verfc( &
     882              :                                     lmax(iset) + nder, npgf(iset), zet(:, iset), rpgf(:, iset), lmin(iset), &
     883              :                                     lmax(jset), npgf(jset), zet(:, jset), rpgf(:, jset), lmin(jset), &
     884              :                                     alpha_c, core_radius, zeta_j, core_charge, &
     885              :                                     [0.0_dp, 0.0_dp, 0.0_dp], 0.0_dp, rab, rab2, rab2, &
     886              :                                     hab(:, :, nij), verf, vnuc, ff(0:), nder, habd)
     887              : 
     888              :                                  ! *** The derivatives w.r.t. atomic center b are    ***
     889              :                                  ! *** calculated using the translational invariance ***
     890              :                                  ! *** of the first derivatives                      ***
     891              :                                  CALL verfc_force(habd, pab(:, :, nij), force_a, force_b, nder, &
     892              :                                                   lmax(iset), lmin(iset), npgf(iset), zet(:, iset), &
     893              :                                                   lmax(jset), lmin(jset), npgf(jset), zet(:, jset), &
     894              :                                                   [0.0_dp, 0.0_dp, 0.0_dp])
     895              : 
     896              :                                  DEALLOCATE (habd)
     897              :                                  force_i = force_a + force_b
     898              : 
     899              :                                  force_thread(1, iatom) = force_thread(1, iatom) + f0*force_i(1)
     900              :                                  force_thread(2, iatom) = force_thread(2, iatom) + f0*force_i(2)
     901              :                                  force_thread(3, iatom) = force_thread(3, iatom) + f0*force_i(3)
     902              : 
     903              :                                  force_thread(1, jatom) = force_thread(1, jatom) - f0*force_i(1)
     904              :                                  force_thread(2, jatom) = force_thread(2, jatom) - f0*force_i(2)
     905              :                                  force_thread(3, jatom) = force_thread(3, jatom) - f0*force_i(3)
     906              : 
     907              :                                  IF (use_virial) THEN
     908              :                                     CALL virial_pair_force(pv_thread, f0, force_i, rab)
     909              :                                  END IF
     910              :                               ELSE
     911              :                                  CALL verfc( &
     912              :                                     lmax(iset), npgf(iset), zet(:, iset), rpgf(:, iset), lmin(iset), &
     913              :                                     lmax(jset), npgf(jset), zet(:, jset), rpgf(:, jset), lmin(jset), &
     914              :                                     alpha_c, core_radius, zeta_j, core_charge, &
     915              :                                     [0.0_dp, 0.0_dp, 0.0_dp], 0.0_dp, rab, rab2, rab2, &
     916              :                                     hab(:, :, nij), verf, vnuc, ff(0:))
     917              :                               END IF
     918              :                            END DO
     919              :                         END DO
     920              :                      END DO
     921              :                   END IF
     922              :                END DO
     923              :                ! *** Contract nuclear repulsion integrals
     924              :                DO iset = 1, nset
     925              :                   ncoa = npgf(iset)*ncoset(lmax(iset))
     926              :                   sgfa = first_sgf(1, iset)
     927              :                   DO jset = 1, iset
     928              :                      ncob = npgf(jset)*ncoset(lmax(jset))
     929              :                      sgfb = first_sgf(1, jset)
     930              :                      nij = jset + (iset - 1)*iset/2
     931              :                      work(1:ncoa, 1:nsgf(jset)) = MATMUL(hab(1:ncoa, 1:ncob, nij), &
     932              :                                                          sphi(1:ncob, sgfb:sgfb + nsgf(jset) - 1))
     933              :                      core(sgfa:sgfa + nsgf(iset) - 1, sgfb:sgfb + nsgf(jset) - 1) = &
     934              :                         core(sgfa:sgfa + nsgf(iset) - 1, sgfb:sgfb + nsgf(jset) - 1) - zeta_i* &
     935              :                         MATMUL(TRANSPOSE(sphi(1:ncoa, sgfa:sgfa + nsgf(iset) - 1)), work(1:ncoa, 1:nsgf(jset)))
     936              :                      ! symmetrize core matrix
     937              :                      IF (iset /= jset) THEN
     938              :                         core(sgfb:sgfb + nsgf(jset) - 1, sgfa:sgfa + nsgf(iset) - 1) = &
     939              :                            TRANSPOSE(core(sgfa:sgfa + nsgf(iset) - 1, sgfb:sgfb + nsgf(jset) - 1))
     940              :                      END IF
     941              :                   END DO
     942              :                END DO
     943              :             END DO
     944              :          END IF
     945              :       END DO
     946              : 
     947              :       DEALLOCATE (hab, work, verf, vnuc, ff)
     948              :       IF (calculate_forces) THEN
     949              :          DEALLOCATE (pab)
     950              :       END IF
     951              : 
     952              : !$OMP END PARALLEL
     953              : 
     954           14 :       CALL neighbor_list_iterator_release(ap_iterator)
     955              : 
     956           14 :       IF (calculate_forces) THEN
     957              :          CALL get_atomic_kind_set(atomic_kind_set, atom_of_kind=atom_of_kind, &
     958            6 :                                   kind_of=kind_of)
     959              : !$OMP DO
     960              :          DO iatom = 1, natom
     961           18 :             atom_a = atom_of_kind(iatom)
     962           18 :             ikind = kind_of(iatom)
     963              :             force(ikind)%cneo_potential(:, atom_a) = force(ikind)%cneo_potential(:, atom_a) + &
     964           72 :                                                      force_thread(:, iatom)
     965              :          END DO
     966              : !$OMP END DO
     967              :       END IF
     968              : 
     969           14 :       IF (calculate_forces .AND. use_virial) THEN
     970            0 :          virial%pv_ppl = virial%pv_ppl + pv_thread
     971            0 :          virial%pv_virial = virial%pv_virial + pv_thread
     972              :       END IF
     973              : 
     974              :       ! broadcast core matrices
     975           40 :       DO ikind = 1, nkind
     976           26 :          NULLIFY (cneo_potential)
     977           26 :          CALL get_qs_kind(qs_kind_set(ikind), cneo_potential=cneo_potential)
     978              : 
     979           40 :          IF (ASSOCIATED(cneo_potential)) THEN
     980           14 :             NULLIFY (atom_list)
     981           14 :             CALL get_atomic_kind(atomic_kind_set(ikind), atom_list=atom_list, natom=nat)
     982           40 :             DO iat = 1, nat
     983           26 :                iatom = atom_list(iat)
     984        28744 :                CALL para_env%sum(rhoz_cneo_set(iatom)%core)
     985              :             END DO
     986              :          END IF
     987              :       END DO
     988              : 
     989           14 :       CALL timestop(handle)
     990              : 
     991           28 :    END SUBROUTINE build_core_cneo
     992              : 
     993              : ! **************************************************************************************************
     994              : !> \brief ...
     995              : !> \param rho ...
     996              : !> \param potential ...
     997              : !> \param cg_list ...
     998              : !> \param cg_n_list ...
     999              : !> \param nset ...
    1000              : !> \param npgf ...
    1001              : !> \param lmin ...
    1002              : !> \param lmax ...
    1003              : !> \param maxl ...
    1004              : !> \param maxso ...
    1005              : ! **************************************************************************************************
    1006           46 :    SUBROUTINE calculate_rhoz_cneo(rho, potential, cg_list, cg_n_list, nset, npgf, &
    1007              :                                   lmin, lmax, maxl, maxso)
    1008              : 
    1009              :       TYPE(rhoz_cneo_type), POINTER                      :: rho
    1010              :       TYPE(cneo_potential_type), POINTER                 :: potential
    1011              :       INTEGER, DIMENSION(:, :, :), INTENT(INOUT)         :: cg_list
    1012              :       INTEGER, DIMENSION(:), INTENT(INOUT)               :: cg_n_list
    1013              :       INTEGER, INTENT(IN)                                :: nset
    1014              :       INTEGER, DIMENSION(:), POINTER                     :: npgf, lmin, lmax
    1015              :       INTEGER, INTENT(IN)                                :: maxl, maxso
    1016              : 
    1017              :       CHARACTER(len=*), PARAMETER :: routineN = 'calculate_rhoz_cneo'
    1018              : 
    1019              :       INTEGER :: handle, i, i1, i2, icg, ipgf1, ipgf2, iset1, iset2, iso, iso1, iso1_first, &
    1020              :          iso1_last, iso2, iso2_first, iso2_last, iter, j, l, l1, l2, l_iso, lmax_expansion, m1s, &
    1021              :          m2s, max_iso_not0, max_iso_not0_local, max_iter, max_s_harm, n1s, n2s, nne, npgf2, npsgf, &
    1022              :          nsgf, nsotot, size1, size2
    1023           46 :       INTEGER, DIMENSION(:), POINTER                     :: n2oindex, o2nindex
    1024              :       REAL(KIND=dp)                                      :: det, df_norm, factor, g0, g0p, g1, step, &
    1025              :                                                             zeff
    1026           46 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: ener
    1027           46 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: CPCH_sphere, CPCS_sphere, work
    1028              :       REAL(KIND=dp), DIMENSION(3)                        :: df, f_tmp, r, r_tmp
    1029              :       REAL(KIND=dp), DIMENSION(3, 3)                     :: jac, jac_inv
    1030           46 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: f
    1031           46 :       REAL(KIND=dp), DIMENSION(:, :), POINTER :: core, cpc_h, cpc_s, fmat, int_local_h, &
    1032           46 :          int_local_s, my_gcc_h, my_gcc_s, pmat, rho_rad_h, rho_rad_s, utrans, vmat, vrho_rad_h, &
    1033           46 :          vrho_rad_s, wfn
    1034           46 :       REAL(KIND=dp), DIMENSION(:, :, :), POINTER         :: distance, gg, my_CG
    1035           46 :       REAL(KIND=dp), DIMENSION(:, :, :, :), POINTER      :: vgg
    1036              :       TYPE(harmonics_atom_type), POINTER                 :: harmonics
    1037              : 
    1038            0 :       CPASSERT(ASSOCIATED(rho))
    1039           46 :       CPASSERT(ASSOCIATED(potential))
    1040              : 
    1041           46 :       CALL timeset(routineN, handle)
    1042              : 
    1043              :       ! convert ga_Vlocal_gb to compressed form V_Hartree
    1044              :       ! use fmat to store V_Hartree
    1045           46 :       NULLIFY (utrans, my_gcc_h, my_gcc_s, distance, n2oindex, o2nindex)
    1046              :       CALL get_cneo_potential(potential, zeff=zeff, nsgf=nsgf, nne=nne, npsgf=npsgf, &
    1047              :                               nsotot=nsotot, my_gcc_h=my_gcc_h, my_gcc_s=my_gcc_s, &
    1048              :                               utrans=utrans, distance=distance, n2oindex=n2oindex, &
    1049           46 :                               o2nindex=o2nindex)
    1050           46 :       fmat => rho%fmat
    1051           46 :       int_local_h => rho%ga_Vlocal_gb_h
    1052           46 :       int_local_s => rho%ga_Vlocal_gb_s
    1053          184 :       ALLOCATE (work(nsotot, nsgf))
    1054              :       CALL dgemm("N", "N", nsotot, nsgf, nsotot, 1.0_dp, int_local_h, nsotot, my_gcc_h, &
    1055           46 :                  nsotot, 0.0_dp, work, nsotot)
    1056              :       CALL dgemm("T", "N", nsgf, nsgf, nsotot, 1.0_dp, my_gcc_h, nsotot, work, &
    1057           46 :                  nsotot, 0.0_dp, fmat, nsgf)
    1058              :       CALL dgemm("N", "N", nsotot, nsgf, nsotot, 1.0_dp, int_local_s, nsotot, my_gcc_s, &
    1059           46 :                  nsotot, 0.0_dp, work, nsotot)
    1060              :       CALL dgemm("T", "N", nsgf, nsgf, nsotot, -1.0_dp, my_gcc_s, nsotot, work, &
    1061           46 :                  nsotot, 1.0_dp, fmat, nsgf)
    1062              :       ! add the soft basis FFT grid part
    1063           46 :       vmat => rho%vmat
    1064        50830 :       fmat = fmat + vmat
    1065              : 
    1066           46 :       core => rho%core
    1067           46 :       wfn => rho%wfn
    1068           46 :       pmat => rho%pmat
    1069           46 :       f => rho%f
    1070          138 :       ALLOCATE (ener(nne))
    1071              :       ! build the fock matrix: F = T + V_core + V_Hartree
    1072        50830 :       fmat = fmat + core
    1073              :       ! conduct the constrained optimization with F + f*x
    1074              :       ! initial guess of f is taken from the result of last iteration
    1075           46 :       CALL atom_solve_cneo(fmat, f, utrans, wfn, ener, pmat, r, distance, nsgf, nne)
    1076              :       ! test if zero initial guess is better
    1077          322 :       IF (SQRT(DOT_PRODUCT(r, r)) > 1.e-12_dp .AND. DOT_PRODUCT(f, f) /= 0.0_dp) THEN
    1078              :          CALL atom_solve_cneo(fmat, [0.0_dp, 0.0_dp, 0.0_dp], utrans, wfn, &
    1079           39 :                               ener, pmat, r_tmp, distance, nsgf, nne)
    1080          273 :          IF (DOT_PRODUCT(r_tmp, r_tmp) < DOT_PRODUCT(r, r)) THEN
    1081           24 :             f = 0.0_dp
    1082            6 :             r = r_tmp
    1083              :          END IF
    1084              :       END IF
    1085           46 :       max_iter = 20
    1086           46 :       iter = 0
    1087              :       ! using Newton's method to solve for f
    1088          884 :       DO WHILE (SQRT(DOT_PRODUCT(r, r)) > 1.e-12_dp)
    1089          140 :          iter = iter + 1
    1090              :          ! construct numerical Jacobian with one-side finite difference
    1091          560 :          DO i = 1, 3
    1092         1680 :             f_tmp = f
    1093          420 :             f_tmp(i) = f(i) + SIGN(1.e-4_dp, r(i)) ! forward or backward based on the sign of r
    1094          420 :             CALL atom_solve_cneo(fmat, f_tmp, utrans, wfn, ener, pmat, r_tmp, distance, nsgf, nne)
    1095         1820 :             DO j = 1, 3
    1096         1680 :                jac(j, i) = (r_tmp(j) - r(j))*SIGN(1.e4_dp, r(i))
    1097              :             END DO
    1098              :          END DO
    1099          140 :          CALL invert_matrix_3x3(jac, jac_inv, det)
    1100          140 :          IF (ABS(det) < 1.0E-8_dp) THEN
    1101              :             CALL cp_warn(__LOCATION__, "Determinant of the CNEO position Jacobian is small! "// &
    1102            0 :                          TRIM(cp_to_string(det))//" Trying central difference.")
    1103              :             ! construct numerical Jacobian with central finite difference
    1104            0 :             DO i = 1, 3
    1105            0 :                f_tmp = f
    1106            0 :                f_tmp(i) = f(i) - SIGN(1.e-4_dp, r(i))
    1107            0 :                CALL atom_solve_cneo(fmat, f_tmp, utrans, wfn, ener, pmat, r_tmp, distance, nsgf, nne)
    1108            0 :                DO j = 1, 3
    1109              :                   jac(j, i) = (jac(j, i)*SIGN(1.e-4_dp, r(i)) + r(j) - r_tmp(j)) &
    1110            0 :                               /SIGN(2.e-4_dp, r(i))
    1111              :                END DO
    1112              :             END DO
    1113            0 :             CALL invert_matrix_3x3(jac, jac_inv, det)
    1114            0 :             IF (ABS(det) < 1.0E-8_dp) THEN
    1115              :                CALL cp_warn(__LOCATION__, "Determinant of the CNEO position Jacobian is small! "// &
    1116            0 :                             "(Central difference) "//TRIM(cp_to_string(det))//" Using pseudoinverse.")
    1117              :             END IF
    1118            0 :             CALL invert_matrix_3x3(jac, jac_inv, det, try_svd=.TRUE.)
    1119              :          END IF
    1120         2380 :          df = -RESHAPE(MATMUL(jac_inv, RESHAPE(r, [3, 1])), [3])
    1121          560 :          df_norm = SQRT(DOT_PRODUCT(df, df))
    1122          560 :          f_tmp = f
    1123          140 :          r_tmp = r
    1124          560 :          g0 = SQRT(DOT_PRODUCT(r_tmp, r_tmp))
    1125          560 :          f = f_tmp + df
    1126          140 :          CALL atom_solve_cneo(fmat, f, utrans, wfn, ener, pmat, r, distance, nsgf, nne)
    1127          560 :          g1 = SQRT(DOT_PRODUCT(r, r))
    1128          140 :          step = 1.0_dp
    1129          140 :          DO WHILE (g1 >= g0)
    1130              :             ! line search
    1131            0 :             IF (step < 0.0101_dp) THEN
    1132            0 :                CPWARN("CNEO nuclear position constraint solver line search failure.")
    1133            0 :                EXIT
    1134              :             END IF
    1135            0 :             g0p = -g0/(step*df_norm)
    1136            0 :             step = step*MAX(-g0p/(2.0_dp*(g1 - g0 - g0p)), 0.1_dp)
    1137            0 :             f = f_tmp + step*df
    1138            0 :             CALL atom_solve_cneo(fmat, f, utrans, wfn, ener, pmat, r, distance, nsgf, nne)
    1139          140 :             g1 = SQRT(DOT_PRODUCT(r, r))
    1140              :          END DO
    1141          280 :          IF (iter >= max_iter) THEN
    1142              :             CALL cp_warn(__LOCATION__, "CNEO nuclear position constraint solver failed to "// &
    1143              :                          "converge in "//TRIM(cp_to_string(max_iter))//" steps. "// &
    1144              :                          "Nuclear position error (x,y,z): "//TRIM(cp_to_string(r(1)))// &
    1145              :                          ", "//TRIM(cp_to_string(r(2)))//", "//TRIM(cp_to_string(r(3)))// &
    1146            0 :                          ". This does not hurt as long as it is not the final SCF iteration.")
    1147            0 :             EXIT
    1148              :          END IF
    1149              :       END DO
    1150           46 :       DEALLOCATE (ener)
    1151           46 :       rho%e_core = trace_r_AxB(core, nsgf, pmat, nsgf, nsgf, nsgf)
    1152              : 
    1153              :       ! decontract the density matrix
    1154              :       ! first use ga_Vlocal_gb to store the decompressed form
    1155              :       CALL dgemm("N", "N", nsotot, nsgf, nsgf, 1.0_dp, my_gcc_h, nsotot, pmat, nsgf, &
    1156           46 :                  0.0_dp, work, nsotot)
    1157              :       CALL dgemm("N", "T", nsotot, nsotot, nsgf, 1.0_dp, work, nsotot, my_gcc_h, nsotot, &
    1158           46 :                  0.0_dp, int_local_h, nsotot)
    1159              :       CALL dgemm("N", "N", nsotot, nsgf, nsgf, 1.0_dp, my_gcc_s, nsotot, pmat, nsgf, &
    1160           46 :                  0.0_dp, work, nsotot)
    1161              :       CALL dgemm("N", "T", nsotot, nsotot, nsgf, 1.0_dp, work, nsotot, my_gcc_s, nsotot, &
    1162           46 :                  0.0_dp, int_local_s, nsotot)
    1163           46 :       DEALLOCATE (work)
    1164              :       ! compress the density matrix
    1165           46 :       cpc_h => rho%cpc_h
    1166           46 :       cpc_s => rho%cpc_s
    1167           46 :       CALL cneo_gather(int_local_h, cpc_h, npsgf, n2oindex)
    1168           46 :       CALL cneo_gather(int_local_s, cpc_s, npsgf, n2oindex)
    1169              :       ! restore ga_Vlocal_gb to zeros
    1170       305578 :       int_local_h = 0.0_dp
    1171       305578 :       int_local_s = 0.0_dp
    1172              : 
    1173              :       ! construct the nuclear density and its Hartree potential
    1174              :       ! rho_rad_h and vrho_rad_h should contain the -Zeff factor
    1175              :       ! mostly copied from qs_rho_atom_methods::calculate_rho_atom
    1176           46 :       NULLIFY (harmonics, gg, vgg)
    1177           46 :       CALL get_cneo_potential(potential, harmonics=harmonics, gg=gg, vgg=vgg)
    1178           46 :       rho_rad_h => rho%rho_rad_h
    1179           46 :       rho_rad_s => rho%rho_rad_s
    1180        58696 :       rho_rad_h = 0.0_dp
    1181        58696 :       rho_rad_s = 0.0_dp
    1182           46 :       vrho_rad_h => rho%vrho_rad_h
    1183           46 :       vrho_rad_s => rho%vrho_rad_s
    1184        58696 :       vrho_rad_h = 0.0_dp
    1185        58696 :       vrho_rad_s = 0.0_dp
    1186           46 :       my_CG => harmonics%my_CG
    1187           46 :       max_iso_not0 = harmonics%max_iso_not0
    1188           46 :       max_s_harm = harmonics%max_s_harm
    1189           46 :       lmax_expansion = indso(1, max_iso_not0)
    1190              : 
    1191          184 :       ALLOCATE (CPCH_sphere(nsoset(maxl), nsoset(maxl)))
    1192          138 :       ALLOCATE (CPCS_sphere(nsoset(maxl), nsoset(maxl)))
    1193           46 :       j = 0
    1194           46 :       m1s = 0
    1195          460 :       DO iset1 = 1, nset
    1196          414 :          m2s = 0
    1197          414 :          n1s = nsoset(lmax(iset1))
    1198         2484 :          DO iset2 = 1, iset1
    1199              : 
    1200              :             CALL get_none0_cg_list(my_CG, lmin(iset1), lmax(iset1), lmin(iset2), lmax(iset2), &
    1201         2070 :                                    max_s_harm, lmax_expansion, cg_list, cg_n_list, max_iso_not0_local)
    1202         2070 :             CPASSERT(max_iso_not0_local <= max_iso_not0)
    1203              : 
    1204         2070 :             n2s = nsoset(lmax(iset2))
    1205         4140 :             DO ipgf1 = 1, npgf(iset1)
    1206         2070 :                iso1_first = nsoset(lmin(iset1) - 1) + 1 + n1s*(ipgf1 - 1) + m1s
    1207         2070 :                iso1_last = nsoset(lmax(iset1)) + n1s*(ipgf1 - 1) + m1s
    1208         2070 :                size1 = iso1_last - iso1_first + 1
    1209         2070 :                iso1_first = o2nindex(iso1_first)
    1210         2070 :                iso1_last = o2nindex(iso1_last)
    1211         2070 :                i1 = iso1_last - iso1_first + 1
    1212         2070 :                CPASSERT(size1 == i1)
    1213         2070 :                i1 = nsoset(lmin(iset1) - 1) + 1
    1214              : 
    1215         2070 :                IF (iset2 == iset1) THEN
    1216              :                   npgf2 = ipgf1
    1217              :                ELSE
    1218         1656 :                   npgf2 = npgf(iset2)
    1219              :                END IF
    1220         6210 :                DO ipgf2 = 1, npgf2
    1221         2070 :                   j = j + 1
    1222         2070 :                   iso2_first = nsoset(lmin(iset2) - 1) + 1 + n2s*(ipgf2 - 1) + m2s
    1223         2070 :                   iso2_last = nsoset(lmax(iset2)) + n2s*(ipgf2 - 1) + m2s
    1224         2070 :                   size2 = iso2_last - iso2_first + 1
    1225         2070 :                   iso2_first = o2nindex(iso2_first)
    1226         2070 :                   iso2_last = o2nindex(iso2_last)
    1227         2070 :                   i2 = iso2_last - iso2_first + 1
    1228         2070 :                   CPASSERT(size2 == i2)
    1229         2070 :                   i2 = nsoset(lmin(iset2) - 1) + 1
    1230              : 
    1231         2070 :                   IF (iset2 == iset1 .AND. ipgf2 == ipgf1) THEN
    1232          414 :                      factor = -zeff
    1233              :                   ELSE
    1234         1656 :                      factor = -2.0_dp*zeff
    1235              :                   END IF
    1236              : 
    1237       188370 :                   CPCH_sphere = 0.0_dp
    1238       188370 :                   CPCS_sphere = 0.0_dp
    1239        19826 :                   CPCH_sphere(i1:i1 + size1 - 1, i2:i2 + size2 - 1) = cpc_h(iso1_first:iso1_last, iso2_first:iso2_last)
    1240        19826 :                   CPCS_sphere(i1:i1 + size1 - 1, i2:i2 + size2 - 1) = cpc_s(iso1_first:iso1_last, iso2_first:iso2_last)
    1241        20470 :                   DO iso = 1, max_iso_not0_local
    1242        16330 :                      l_iso = indso(1, iso)
    1243        44298 :                      DO icg = 1, cg_n_list(iso)
    1244        25898 :                         iso1 = cg_list(1, icg, iso)
    1245        25898 :                         iso2 = cg_list(2, icg, iso)
    1246              : 
    1247        25898 :                         l1 = indso(1, iso1)
    1248        25898 :                         l2 = indso(1, iso2)
    1249              : 
    1250        25898 :                         l = indso(1, iso1) + indso(1, iso2)
    1251        25898 :                         CPASSERT(l <= lmax_expansion)
    1252              : 
    1253              :                         rho_rad_h(:, iso) = rho_rad_h(:, iso) + gg(:, l, j)* &
    1254      2615698 :                                             CPCH_sphere(iso1, iso2)*my_CG(iso1, iso2, iso)*factor
    1255              : 
    1256              :                         rho_rad_s(:, iso) = rho_rad_s(:, iso) + gg(:, l, j)* &
    1257      2615698 :                                             CPCS_sphere(iso1, iso2)*my_CG(iso1, iso2, iso)*factor
    1258              : 
    1259              :                         vrho_rad_h(:, iso) = vrho_rad_h(:, iso) + vgg(:, l, l_iso, j)* &
    1260      2615698 :                                              CPCH_sphere(iso1, iso2)*my_CG(iso1, iso2, iso)*factor
    1261              : 
    1262              :                         vrho_rad_s(:, iso) = vrho_rad_s(:, iso) + vgg(:, l, l_iso, j)* &
    1263      2632028 :                                              CPCS_sphere(iso1, iso2)*my_CG(iso1, iso2, iso)*factor
    1264              :                      END DO ! icg
    1265              :                   END DO ! iso
    1266              :                END DO ! ipgf2
    1267              :             END DO ! ipgf1
    1268         2484 :             m2s = m2s + maxso
    1269              :          END DO ! iset2
    1270          460 :          m1s = m1s + maxso
    1271              :       END DO ! iset1
    1272           46 :       DEALLOCATE (CPCH_sphere, CPCS_sphere)
    1273              : 
    1274           46 :       CALL timestop(handle)
    1275              : 
    1276           92 :    END SUBROUTINE calculate_rhoz_cneo
    1277              : 
    1278              : ! **************************************************************************************************
    1279              : !> \brief Mostly copied from hartree_local_methods::Vh_1c_atom_integrals
    1280              : !> \param rhoz_cneo ...
    1281              : !> \param zeff ...
    1282              : !> \param aVh1b_hh ...
    1283              : !> \param aVh1b_ss ...
    1284              : !> \param aVh1b_00 ...
    1285              : !> \param Vh1_h ...
    1286              : !> \param Vh1_s ...
    1287              : !> \param max_iso_not0_elec ...
    1288              : !> \param max_iso_not0_nuc ...
    1289              : !> \param max_s_harm ...
    1290              : !> \param llmax ...
    1291              : !> \param cg_list ...
    1292              : !> \param cg_n_list ...
    1293              : !> \param nset ...
    1294              : !> \param npgf ...
    1295              : !> \param lmin ...
    1296              : !> \param lmax ...
    1297              : !> \param nsotot ...
    1298              : !> \param maxso ...
    1299              : !> \param nchan_0 ...
    1300              : !> \param gsph ...
    1301              : !> \param g0_h_w ...
    1302              : !> \param my_CG ...
    1303              : !> \param Qlm_gg ...
    1304              : ! **************************************************************************************************
    1305           46 :    SUBROUTINE Vh_1c_nuc_integrals(rhoz_cneo, zeff, &
    1306           46 :                                   aVh1b_hh, aVh1b_ss, aVh1b_00, Vh1_h, Vh1_s, &
    1307              :                                   max_iso_not0_elec, max_iso_not0_nuc, &
    1308           46 :                                   max_s_harm, llmax, cg_list, cg_n_list, &
    1309              :                                   nset, npgf, lmin, lmax, nsotot, maxso, nchan_0, gsph, &
    1310           46 :                                   g0_h_w, my_CG, Qlm_gg)
    1311              : 
    1312              :       TYPE(rhoz_cneo_type), POINTER                      :: rhoz_cneo
    1313              :       REAL(KIND=dp), INTENT(IN)                          :: zeff
    1314              :       REAL(KIND=dp), DIMENSION(:, :)                     :: aVh1b_hh, aVh1b_ss, aVh1b_00
    1315              :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: Vh1_h, Vh1_s
    1316              :       INTEGER, INTENT(IN)                                :: max_iso_not0_elec, max_iso_not0_nuc, &
    1317              :                                                             max_s_harm, llmax
    1318              :       INTEGER, DIMENSION(:, :, :)                        :: cg_list
    1319              :       INTEGER, DIMENSION(:)                              :: cg_n_list
    1320              :       INTEGER, INTENT(IN)                                :: nset
    1321              :       INTEGER, DIMENSION(:), POINTER                     :: npgf, lmin, lmax
    1322              :       INTEGER, INTENT(IN)                                :: nsotot, maxso, nchan_0
    1323              :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: gsph
    1324              :       REAL(KIND=dp), DIMENSION(:, 0:)                    :: g0_h_w
    1325              :       REAL(KIND=dp), DIMENSION(:, :, :), POINTER         :: my_CG, Qlm_gg
    1326              : 
    1327              :       INTEGER                                            :: icg, ipgf1, ipgf2, ir, is1, is2, iset1, &
    1328              :                                                             iset2, iso, iso1, iso2, l_ang, m1, m2, &
    1329              :                                                             max_iso_not0_local, n1, n2, nr
    1330              :       REAL(KIND=dp)                                      :: gVg_0, gVg_h, gVg_s
    1331              : 
    1332              :       !       Calculate the integrals of the potential with 2 primitives
    1333       305578 :       aVh1b_hh = 0.0_dp
    1334       305578 :       aVh1b_ss = 0.0_dp
    1335       305578 :       aVh1b_00 = 0.0_dp
    1336              : 
    1337           46 :       nr = SIZE(gsph, 1)
    1338              : 
    1339           46 :       m1 = 0
    1340          460 :       DO iset1 = 1, nset
    1341          414 :          n1 = nsoset(lmax(iset1))
    1342          414 :          m2 = 0
    1343         4140 :          DO iset2 = 1, nset
    1344              :             CALL get_none0_cg_list(my_CG, lmin(iset1), lmax(iset1), lmin(iset2), lmax(iset2), &
    1345         3726 :                                    max_s_harm, llmax, cg_list, cg_n_list, max_iso_not0_local)
    1346              : 
    1347         3726 :             n2 = nsoset(lmax(iset2))
    1348         7452 :             DO ipgf1 = 1, npgf(iset1)
    1349        11178 :                DO ipgf2 = 1, npgf(iset2)
    1350        37260 :                   DO iso = 1, MIN(max_iso_not0_elec, max_iso_not0_nuc)
    1351        62376 :                      DO icg = 1, cg_n_list(iso)
    1352        25116 :                         is1 = cg_list(1, icg, iso)
    1353        25116 :                         is2 = cg_list(2, icg, iso)
    1354              : 
    1355        25116 :                         iso1 = is1 + n1*(ipgf1 - 1) + m1
    1356        25116 :                         iso2 = is2 + n2*(ipgf2 - 1) + m2
    1357        25116 :                         gVg_h = 0.0_dp
    1358        25116 :                         gVg_s = 0.0_dp
    1359              : 
    1360      1280916 :                         DO ir = 1, nr
    1361      1255800 :                            gVg_h = gVg_h + gsph(ir, iso1)*gsph(ir, iso2)*Vh1_h(ir, iso)
    1362      1280916 :                            gVg_s = gVg_s + gsph(ir, iso1)*gsph(ir, iso2)*Vh1_s(ir, iso)
    1363              :                         END DO ! ir
    1364              : 
    1365        25116 :                         aVh1b_hh(iso1, iso2) = aVh1b_hh(iso1, iso2) + gVg_h*my_CG(is1, is2, iso)
    1366        58650 :                         aVh1b_ss(iso1, iso2) = aVh1b_ss(iso1, iso2) + gVg_s*my_CG(is1, is2, iso)
    1367              : 
    1368              :                      END DO !icg
    1369              :                   END DO ! iso
    1370        63342 :                   DO iso = max_iso_not0_elec + 1, max_iso_not0_nuc
    1371        81742 :                      DO icg = 1, cg_n_list(iso)
    1372        18400 :                         is1 = cg_list(1, icg, iso)
    1373        18400 :                         is2 = cg_list(2, icg, iso)
    1374              : 
    1375        18400 :                         iso1 = is1 + n1*(ipgf1 - 1) + m1
    1376        18400 :                         iso2 = is2 + n2*(ipgf2 - 1) + m2
    1377        18400 :                         gVg_s = 0.0_dp
    1378              : 
    1379       938400 :                         DO ir = 1, nr
    1380       938400 :                            gVg_s = gVg_s + gsph(ir, iso1)*gsph(ir, iso2)*Vh1_s(ir, iso)
    1381              :                         END DO ! ir
    1382              : 
    1383        78016 :                         aVh1b_ss(iso1, iso2) = aVh1b_ss(iso1, iso2) + gVg_s*my_CG(is1, is2, iso)
    1384              : 
    1385              :                      END DO !icg
    1386              :                   END DO ! iso
    1387        40986 :                   DO iso = 1, MIN(nchan_0, max_iso_not0_nuc)
    1388        33534 :                      l_ang = indso(1, iso)
    1389      1710234 :                      gVg_0 = SUM(Vh1_s(:, iso)*g0_h_w(:, l_ang))
    1390        62376 :                      DO icg = 1, cg_n_list(iso)
    1391        25116 :                         is1 = cg_list(1, icg, iso)
    1392        25116 :                         is2 = cg_list(2, icg, iso)
    1393              : 
    1394        25116 :                         iso1 = is1 + n1*(ipgf1 - 1) + m1
    1395        25116 :                         iso2 = is2 + n2*(ipgf2 - 1) + m2
    1396              : 
    1397        58650 :                         aVh1b_00(iso1, iso2) = aVh1b_00(iso1, iso2) + gVg_0*Qlm_gg(iso1, iso2, iso)
    1398              : 
    1399              :                      END DO !icg
    1400              :                   END DO ! iso
    1401              :                END DO ! ipgf2
    1402              :             END DO ! ipgf1
    1403         4140 :             m2 = m2 + maxso
    1404              :          END DO ! iset2
    1405          460 :          m1 = m1 + maxso
    1406              :       END DO !iset1
    1407              : 
    1408           46 :       CALL daxpy(nsotot*nsotot, -zeff, aVh1b_hh, 1, rhoz_cneo%ga_Vlocal_gb_h, 1)
    1409           46 :       CALL daxpy(nsotot*nsotot, -zeff, aVh1b_ss, 1, rhoz_cneo%ga_Vlocal_gb_s, 1)
    1410           46 :       CALL daxpy(nsotot*nsotot, zeff, aVh1b_00, 1, rhoz_cneo%ga_Vlocal_gb_h, 1)
    1411           46 :       CALL daxpy(nsotot*nsotot, zeff, aVh1b_00, 1, rhoz_cneo%ga_Vlocal_gb_s, 1)
    1412              : 
    1413           46 :    END SUBROUTINE Vh_1c_nuc_integrals
    1414              : 
    1415              : ! **************************************************************************************************
    1416              : !> \brief Analytical inversion of a 3x3 matrix
    1417              : !> \param matrix ...
    1418              : !> \param inv_matrix ...
    1419              : !> \param det ...
    1420              : !> \param try_svd ...
    1421              : ! **************************************************************************************************
    1422          140 :    SUBROUTINE invert_matrix_3x3(matrix, inv_matrix, det, try_svd)
    1423              :       REAL(KIND=dp), DIMENSION(3, 3), INTENT(IN)         :: matrix
    1424              :       REAL(KIND=dp), DIMENSION(3, 3), INTENT(OUT)        :: inv_matrix
    1425              :       REAL(KIND=dp), INTENT(OUT)                         :: det
    1426              :       LOGICAL, INTENT(IN), OPTIONAL                      :: try_svd
    1427              : 
    1428              :       LOGICAL                                            :: my_try_svd
    1429              : 
    1430          140 :       my_try_svd = .FALSE.
    1431          140 :       IF (PRESENT(try_svd)) my_try_svd = try_svd
    1432              : 
    1433              :       det = matrix(1, 1)*(matrix(2, 2)*matrix(3, 3) - matrix(2, 3)*matrix(3, 2)) &
    1434              :             - matrix(1, 2)*(matrix(2, 1)*matrix(3, 3) - matrix(2, 3)*matrix(3, 1)) &
    1435          140 :             + matrix(1, 3)*(matrix(2, 1)*matrix(3, 2) - matrix(2, 2)*matrix(3, 1))
    1436          140 :       IF (ABS(det) < 1.0E-8_dp) THEN
    1437            0 :          IF (my_try_svd) THEN
    1438              :             ! pseudo inverse using SVD
    1439            0 :             CALL get_pseudo_inverse_svd(matrix, inv_matrix, 1.0E-6_dp, det)
    1440              :          ELSE
    1441            0 :             inv_matrix = 0.0_dp
    1442              :          END IF
    1443              :       ELSE
    1444          140 :          inv_matrix(1, 1) = matrix(2, 2)*matrix(3, 3) - matrix(2, 3)*matrix(3, 2)
    1445          140 :          inv_matrix(1, 2) = matrix(1, 3)*matrix(3, 2) - matrix(1, 2)*matrix(3, 3)
    1446          140 :          inv_matrix(1, 3) = matrix(1, 2)*matrix(2, 3) - matrix(1, 3)*matrix(2, 2)
    1447          140 :          inv_matrix(2, 1) = matrix(2, 3)*matrix(3, 1) - matrix(2, 1)*matrix(3, 3)
    1448          140 :          inv_matrix(2, 2) = matrix(1, 1)*matrix(3, 3) - matrix(1, 3)*matrix(3, 1)
    1449          140 :          inv_matrix(2, 3) = matrix(1, 3)*matrix(2, 1) - matrix(1, 1)*matrix(2, 3)
    1450          140 :          inv_matrix(3, 1) = matrix(2, 1)*matrix(3, 2) - matrix(2, 2)*matrix(3, 1)
    1451          140 :          inv_matrix(3, 2) = matrix(1, 2)*matrix(3, 1) - matrix(1, 1)*matrix(3, 2)
    1452          140 :          inv_matrix(3, 3) = matrix(1, 1)*matrix(2, 2) - matrix(1, 2)*matrix(2, 1)
    1453         1820 :          inv_matrix = inv_matrix/det
    1454              :       END IF
    1455          140 :    END SUBROUTINE invert_matrix_3x3
    1456              : 
    1457              : END MODULE qs_cneo_methods
        

Generated by: LCOV version 2.0-1