LCOV - code coverage report
Current view: top level - src - qs_ks_atom.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:123285f) Lines: 99.3 % 151 150
Test Date: 2026-11-04 00:58:17 Functions: 100.0 % 2 2

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2026 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \brief routines that build the Kohn-Sham matrix  contributions
      10              : !>      coming from local atomic densities
      11              : ! **************************************************************************************************
      12              : MODULE qs_ks_atom
      13              : 
      14              :    USE ao_util,                         ONLY: trace_r_AxB
      15              :    USE atomic_kind_types,               ONLY: atomic_kind_type,&
      16              :                                               get_atomic_kind,&
      17              :                                               get_atomic_kind_set
      18              :    USE basis_set_types,                 ONLY: gto_basis_set_p_type,&
      19              :                                               gto_basis_set_type
      20              :    USE cp_array_utils,                  ONLY: cp_2d_r_p_type
      21              :    USE cp_control_types,                ONLY: dft_control_type
      22              :    USE cp_dbcsr_api,                    ONLY: dbcsr_get_block_p,&
      23              :                                               dbcsr_p_type
      24              :    USE kinds,                           ONLY: dp,&
      25              :                                               int_8
      26              :    USE kpoint_types,                    ONLY: get_kpoint_info,&
      27              :                                               kpoint_type
      28              :    USE message_passing,                 ONLY: mp_para_env_type
      29              :    USE qs_environment_types,            ONLY: get_qs_env,&
      30              :                                               qs_environment_type
      31              :    USE qs_force_types,                  ONLY: qs_force_type
      32              :    USE qs_kind_types,                   ONLY: get_qs_kind,&
      33              :                                               get_qs_kind_set,&
      34              :                                               qs_kind_type
      35              :    USE qs_neighbor_list_types,          ONLY: get_iterator_task,&
      36              :                                               neighbor_list_iterate,&
      37              :                                               neighbor_list_iterator_create,&
      38              :                                               neighbor_list_iterator_p_type,&
      39              :                                               neighbor_list_iterator_release,&
      40              :                                               neighbor_list_set_p_type,&
      41              :                                               neighbor_list_task_type
      42              :    USE qs_nl_hash_table_types,          ONLY: nl_hash_table_add,&
      43              :                                               nl_hash_table_create,&
      44              :                                               nl_hash_table_get_from_index,&
      45              :                                               nl_hash_table_is_null,&
      46              :                                               nl_hash_table_obj,&
      47              :                                               nl_hash_table_release,&
      48              :                                               nl_hash_table_status
      49              :    USE qs_oce_methods,                  ONLY: prj_gather
      50              :    USE qs_oce_types,                    ONLY: oce_matrix_type
      51              :    USE qs_rho_atom_types,               ONLY: get_rho_atom,&
      52              :                                               rho_atom_coeff,&
      53              :                                               rho_atom_type
      54              :    USE sap_kind_types,                  ONLY: alist_post_align_blk,&
      55              :                                               alist_pre_align_blk,&
      56              :                                               alist_type,&
      57              :                                               get_alist
      58              :    USE util,                            ONLY: get_limit
      59              :    USE virial_methods,                  ONLY: virial_pair_force
      60              :    USE virial_types,                    ONLY: virial_type
      61              : 
      62              : !$ USE OMP_LIB, ONLY: omp_get_max_threads, &
      63              : !$                    omp_get_thread_num, &
      64              : !$                    omp_lock_kind, &
      65              : !$                    omp_init_lock, omp_set_lock, &
      66              : !$                    omp_unset_lock, omp_destroy_lock
      67              : 
      68              : #include "./base/base_uses.f90"
      69              : 
      70              :    IMPLICIT NONE
      71              : 
      72              :    PRIVATE
      73              : 
      74              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_ks_atom'
      75              : 
      76              :    PUBLIC :: update_ks_atom
      77              : 
      78              : CONTAINS
      79              : 
      80              : ! **************************************************************************************************
      81              : !> \brief The correction to the KS matrix due to the GAPW local terms to the hartree and
      82              : !>      XC contributions is here added. The correspondig forces contribution are also calculated
      83              : !>      if required. Each sparse-matrix block A-B is corrected by all the atomic contributions
      84              : !>      centered on atoms C for which the triplet A-C-B exists (they are close enough)
      85              : !>      To this end special lists are used
      86              : !> \param qs_env qs environment, for the lists, the contraction coefficients and the
      87              : !>               pre calculated integrals of the potential with the atomic orbitals
      88              : !> \param ksmat KS matrix, sparse matrix
      89              : !> \param pmat density matrix, sparse matrix, needed only for the forces
      90              : !> \param forces switch for the calculation of the forces on atoms
      91              : !> \param tddft switch for TDDFT linear response
      92              : !> \param rho_atom_external ...
      93              : !> \param kind_set_external ...
      94              : !> \param oce_external ...
      95              : !> \param sab_external ...
      96              : !> \param kscale ...
      97              : !> \param kintegral ...
      98              : !> \param kforce ...
      99              : !> \param fscale ...
     100              : !> \par History
     101              : !>      created [MI]
     102              : !>      the loop over the spins is done internally [03-05,MI]
     103              : !>      Rewrite using new OCE matrices [08.02.09, jhu]
     104              : !>      Add OpenMP [Apr 2016, EPCC]
     105              : !>      Allow for external kind_set, rho_atom_set, oce, sab 12.2019 (A. Bussy)
     106              : ! **************************************************************************************************
     107        41308 :    SUBROUTINE update_ks_atom(qs_env, ksmat, pmat, forces, tddft, rho_atom_external, &
     108              :                              kind_set_external, oce_external, sab_external, kscale, &
     109              :                              kintegral, kforce, fscale)
     110              : 
     111              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     112              :       TYPE(dbcsr_p_type), DIMENSION(*), INTENT(INOUT)    :: ksmat, pmat
     113              :       LOGICAL, INTENT(IN)                                :: forces
     114              :       LOGICAL, INTENT(IN), OPTIONAL                      :: tddft
     115              :       TYPE(rho_atom_type), DIMENSION(:), OPTIONAL, &
     116              :          POINTER                                         :: rho_atom_external
     117              :       TYPE(qs_kind_type), DIMENSION(:), OPTIONAL, &
     118              :          POINTER                                         :: kind_set_external
     119              :       TYPE(oce_matrix_type), OPTIONAL, POINTER           :: oce_external
     120              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
     121              :          OPTIONAL, POINTER                               :: sab_external
     122              :       REAL(KIND=dp), INTENT(IN), OPTIONAL                :: kscale, kintegral, kforce
     123              :       REAL(KIND=dp), DIMENSION(2), INTENT(IN), OPTIONAL  :: fscale
     124              : 
     125              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'update_ks_atom'
     126              : 
     127              :       INTEGER :: bo(2), handle, ia_kind, iac, iat, iatom, ibc, ikind, img, ip, ispin, ja_kind, &
     128              :          jatom, jkind, ka_kind, kac, katom, kbc, kkind, max_gau, max_nsgf, n_cont_a, n_cont_b, &
     129              :          nat, natom, nimages, nkind, nl_table_num_slots, nsoctot, nspins, slot_num
     130              :       INTEGER(KIND=int_8)                                :: nl_table_key
     131        41308 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: atom_of_kind
     132              :       INTEGER, DIMENSION(3)                              :: cell_b
     133        41308 :       INTEGER, DIMENSION(:), POINTER                     :: atom_list, list_a, list_b
     134        41308 :       INTEGER, DIMENSION(:, :, :), POINTER               :: cell_to_index
     135              :       LOGICAL                                            :: dista, distb, do_forces, found, &
     136              :                                                             is_entry_null, is_task_valid, &
     137              :                                                             my_tddft, paw_atom, use_virial
     138        41308 :       LOGICAL, ALLOCATABLE, DIMENSION(:)                 :: has_intac, paw_kind
     139        41308 :       REAL(dp), ALLOCATABLE, DIMENSION(:, :)             :: a_matrix, p_matrix
     140              :       REAL(dp), DIMENSION(3)                             :: rac, rbc
     141              :       REAL(dp), DIMENSION(3, 3)                          :: force_tmp
     142              :       REAL(kind=dp)                                      :: eps_cpc, factor1, factor2
     143        41308 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: C_int_h, C_int_s, coc
     144              :       REAL(KIND=dp), DIMENSION(2)                        :: force_fac
     145              :       REAL(KIND=dp), DIMENSION(3, 3)                     :: pv_virial_thread
     146        41308 :       REAL(KIND=dp), DIMENSION(:, :, :), POINTER         :: C_coeff_hh_a, C_coeff_hh_b, &
     147        41308 :                                                             C_coeff_ss_a, C_coeff_ss_b
     148              :       TYPE(alist_type), POINTER                          :: alist_ac, alist_bc
     149        41308 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
     150        41308 :       TYPE(cp_2d_r_p_type), DIMENSION(:), POINTER        :: mat_h, mat_p
     151              :       TYPE(dft_control_type), POINTER                    :: dft_control
     152        41308 :       TYPE(gto_basis_set_p_type), DIMENSION(:), POINTER  :: basis_set_list
     153              :       TYPE(gto_basis_set_type), POINTER                  :: basis_set_a, basis_set_b
     154              :       TYPE(kpoint_type), POINTER                         :: kpoints
     155              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     156              :       TYPE(neighbor_list_iterator_p_type), &
     157        41308 :          DIMENSION(:), POINTER                           :: nl_iterator
     158              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
     159        41308 :          POINTER                                         :: my_sab
     160              :       TYPE(neighbor_list_task_type), POINTER             :: next_task, task
     161              :       TYPE(nl_hash_table_obj)                            :: nl_hash_table
     162              :       TYPE(oce_matrix_type), POINTER                     :: my_oce
     163        41308 :       TYPE(qs_force_type), DIMENSION(:), POINTER         :: force
     164        41308 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: my_kind_set
     165        41308 :       TYPE(rho_atom_coeff), DIMENSION(:), POINTER        :: int_local_h, int_local_s
     166        41308 :       TYPE(rho_atom_type), DIMENSION(:), POINTER         :: my_rho_atom
     167              :       TYPE(rho_atom_type), POINTER                       :: rho_at
     168              :       TYPE(virial_type), POINTER                         :: virial
     169              : 
     170        41308 : !$    INTEGER(kind=omp_lock_kind), ALLOCATABLE, DIMENSION(:) :: locks
     171              : !$    INTEGER                                            :: lock_num
     172              : 
     173        41308 :       CALL timeset(routineN, handle)
     174              : 
     175        41308 :       NULLIFY (my_kind_set, atomic_kind_set, force, my_oce, para_env, my_rho_atom, my_sab)
     176        41308 :       NULLIFY (mat_h, mat_p, dft_control)
     177              : 
     178              :       CALL get_qs_env(qs_env=qs_env, &
     179              :                       qs_kind_set=my_kind_set, &
     180              :                       atomic_kind_set=atomic_kind_set, &
     181              :                       force=force, &
     182              :                       oce=my_oce, &
     183              :                       para_env=para_env, &
     184              :                       rho_atom_set=my_rho_atom, &
     185              :                       virial=virial, &
     186              :                       sab_orb=my_sab, &
     187        41308 :                       dft_control=dft_control)
     188              : 
     189        41308 :       nspins = dft_control%nspins
     190        41308 :       nimages = dft_control%nimages
     191              : 
     192        41308 :       factor1 = 1.0_dp
     193        41308 :       factor2 = 1.0_dp
     194              : 
     195              :       !deal with externals
     196        41308 :       my_tddft = .FALSE.
     197        41308 :       IF (PRESENT(tddft)) my_tddft = tddft
     198        11766 :       IF (my_tddft) THEN
     199         6028 :          IF (nspins == 1) factor1 = 2.0_dp
     200         6028 :          CPASSERT(nimages == 1)
     201              :       END IF
     202        41308 :       IF (PRESENT(kscale)) THEN
     203          256 :          factor1 = factor1*kscale
     204          256 :          factor2 = factor2*kscale
     205              :       END IF
     206        41308 :       IF (PRESENT(kintegral)) factor1 = kintegral
     207        41308 :       IF (PRESENT(kforce)) factor2 = kforce
     208       123924 :       force_fac = 1.0_dp
     209        41308 :       IF (PRESENT(fscale)) force_fac(:) = fscale(:)
     210              : 
     211        41308 :       IF (PRESENT(rho_atom_external)) my_rho_atom => rho_atom_external
     212        41308 :       IF (PRESENT(kind_set_external)) my_kind_set => kind_set_external
     213        41308 :       IF (PRESENT(oce_external)) my_oce => oce_external
     214        41308 :       IF (PRESENT(sab_external)) my_sab => sab_external
     215              : 
     216              :       ! kpoint images
     217        41308 :       NULLIFY (cell_to_index)
     218        41308 :       IF (nimages > 1) THEN
     219          628 :          CALL get_qs_env(qs_env=qs_env, kpoints=kpoints)
     220          628 :          CALL get_kpoint_info(kpoint=kpoints, cell_to_index=cell_to_index)
     221              :       END IF
     222              : 
     223        41308 :       eps_cpc = dft_control%qs_control%gapw_control%eps_cpc
     224              : 
     225        41308 :       CALL get_atomic_kind_set(atomic_kind_set, natom=natom)
     226        41308 :       CALL get_qs_kind_set(my_kind_set, maxsgf=max_nsgf, maxgtops=max_gau, basis_type="GAPW_1C")
     227              : 
     228        41308 :       IF (forces) THEN
     229         1992 :          CALL get_atomic_kind_set(atomic_kind_set, atom_of_kind=atom_of_kind)
     230         1992 :          use_virial = virial%pv_availability .AND. (.NOT. virial%pv_numer)
     231              :       ELSE
     232              :          use_virial = .FALSE.
     233              :       END IF
     234              : 
     235        41308 :       pv_virial_thread(:, :) = 0.0_dp ! always initialize to avoid floating point exceptions in OMP REDUCTION
     236              : 
     237        41308 :       nkind = SIZE(my_kind_set, 1)
     238              :       ! Collect the local potential contributions from all the processors
     239              :       ASSOCIATE (mepos => para_env%mepos, num_pe => para_env%num_pe)
     240       121456 :       DO ikind = 1, nkind
     241        80148 :          NULLIFY (atom_list)
     242        80148 :          CALL get_atomic_kind(atomic_kind_set(ikind), atom_list=atom_list, natom=nat)
     243        80148 :          CALL get_qs_kind(my_kind_set(ikind), paw_atom=paw_atom)
     244       121456 :          IF (paw_atom) THEN
     245              :             ! gather the atomic block integrals in a more compressed format
     246        71892 :             bo = get_limit(nat, num_pe, mepos)
     247       127017 :             DO iat = bo(1), bo(2)
     248        55125 :                iatom = atom_list(iat)
     249       189542 :                DO ispin = 1, nspins
     250              :                   CALL prj_gather(my_rho_atom(iatom)%ga_Vlocal_gb_h(ispin)%r_coef, &
     251        62525 :                                   my_rho_atom(iatom)%int_scr_h(ispin)%r_coef, my_kind_set(ikind))
     252              :                   CALL prj_gather(my_rho_atom(iatom)%ga_Vlocal_gb_s(ispin)%r_coef, &
     253       117650 :                                   my_rho_atom(iatom)%int_scr_s(ispin)%r_coef, my_kind_set(ikind))
     254              :                END DO
     255              :             END DO
     256              :             ! broadcast the CPC arrays to all processors (replicated data)
     257       215676 :             DO ip = 0, num_pe - 1
     258       143784 :                bo = get_limit(nat, num_pe, ip)
     259       325926 :                DO iat = bo(1), bo(2)
     260       110250 :                   iatom = atom_list(iat)
     261       379084 :                   DO ispin = 1, nspins
     262    120728050 :                      CALL para_env%bcast(my_rho_atom(iatom)%int_scr_h(ispin)%r_coef, ip)
     263    120838300 :                      CALL para_env%bcast(my_rho_atom(iatom)%int_scr_s(ispin)%r_coef, ip)
     264              :                   END DO
     265              :                END DO
     266              :             END DO
     267              :          END IF
     268              :       END DO
     269              :       END ASSOCIATE
     270              : 
     271       204072 :       ALLOCATE (basis_set_list(nkind))
     272       206540 :       ALLOCATE (paw_kind(nkind), has_intac(nkind*nkind))
     273        41308 :       paw_kind(:) = .FALSE.
     274        41308 :       has_intac(:) = .FALSE.
     275       121456 :       DO ikind = 1, nkind
     276        80148 :          CALL get_qs_kind(my_kind_set(ikind), basis_set=basis_set_a, paw_atom=paw_kind(ikind))
     277       121456 :          IF (ASSOCIATED(basis_set_a)) THEN
     278        80148 :             basis_set_list(ikind)%gto_basis_set => basis_set_a
     279              :          ELSE
     280            0 :             NULLIFY (basis_set_list(ikind)%gto_basis_set)
     281              :          END IF
     282              :       END DO
     283       211912 :       DO ikind = 1, nkind*nkind
     284       211912 :          has_intac(ikind) = ASSOCIATED(my_oce%intac(ikind)%alist)
     285              :       END DO
     286              : 
     287              :       ! build the hash table in serial...
     288              :       ! ... creation ...
     289        41308 :       CALL neighbor_list_iterator_create(nl_iterator, my_sab)
     290        41308 :       nl_table_num_slots = natom*natom/2 ! this is probably not optimal, but it seems a good start
     291        41308 :       CALL nl_hash_table_create(nl_hash_table, nmax=nl_table_num_slots)
     292              :       ! ... and population
     293      1147803 :       DO WHILE (neighbor_list_iterate(nl_iterator) == 0) ! build hash table in serial, so don't pass mepos
     294      9958455 :          ALLOCATE (task) ! They must be deallocated before the nl_hash_table is released
     295      1106495 :          CALL get_iterator_task(nl_iterator, task) ! build hash table in serial, so don't pass mepos
     296              :          ! tasks with the same key access the same blocks of H & P
     297      1106495 :          IF (task%iatom <= task%jatom) THEN
     298       665606 :             nl_table_key = natom*task%iatom + task%jatom
     299              :          ELSE
     300       440889 :             nl_table_key = natom*task%jatom + task%iatom
     301              :          END IF
     302      1106495 :          CALL nl_hash_table_add(nl_hash_table, nl_table_key, task)
     303              :       END DO
     304        41308 :       CALL neighbor_list_iterator_release(nl_iterator)
     305              : 
     306              :       ! Get the total number of (possibly empty) entries in the table
     307        41308 :       CALL nl_hash_table_status(nl_hash_table, nmax=nl_table_num_slots)
     308              : 
     309              : !$OMP PARALLEL DEFAULT(NONE)                                         &
     310              : !$OMP           SHARED(nl_table_num_slots, nl_hash_table             &
     311              : !$OMP                 , max_gau, max_nsgf, nspins, forces            &
     312              : !$OMP                 , basis_set_list, nimages, cell_to_index       &
     313              : !$OMP                 , ksmat, pmat, natom, nkind, my_kind_set, my_oce &
     314              : !$OMP                 , my_rho_atom, factor1, factor2, use_virial    &
     315              : !$OMP                 , atom_of_kind, force, locks, force_fac        &
     316              : !$OMP                 , paw_kind, has_intac                          &
     317              : !$OMP                 )                                              &
     318              : !$OMP          PRIVATE( slot_num, is_entry_null, TASK, is_task_valid &
     319              : !$OMP                 , C_int_h, C_int_s, coc, a_matrix, p_matrix    &
     320              : !$OMP                 , mat_h, mat_p                               &
     321              : !$OMP                 , int_local_h, int_local_s                     &
     322              : !$OMP                 , ikind, jkind, iatom, jatom, cell_b           &
     323              : !$OMP                 , basis_set_a, basis_set_b, img                &
     324              : !$OMP                 , found, next_task                             &
     325              : !$OMP                 , kkind, lock_num                              &
     326              : !$OMP                 , iac, alist_ac, kac, n_cont_a, list_a         &
     327              : !$OMP                 , ibc, alist_bc, kbc, n_cont_b, list_b         &
     328              : !$OMP                 , katom, rho_at, nsoctot                       &
     329              : !$OMP                 , C_coeff_hh_a, C_coeff_ss_a, dista, rac       &
     330              : !$OMP                 , C_coeff_hh_b, C_coeff_ss_b, distb, rbc       &
     331              : !$OMP                 , ia_kind, ja_kind, ka_kind, force_tmp, do_forces &
     332              : !$OMP                 )                                              &
     333              : !$OMP        REDUCTION(+:pv_virial_thread                            &
     334        41308 : !$OMP                 )
     335              : 
     336              :       ALLOCATE (C_int_h(max_gau*max_nsgf), C_int_s(max_gau*max_nsgf), coc(max_gau*max_gau), &
     337              :                 a_matrix(max_gau, max_gau), p_matrix(max_nsgf, max_nsgf))
     338              : 
     339              :       ALLOCATE (mat_h(nspins), mat_p(nspins))
     340              :       DO ispin = 1, nspins
     341              :          NULLIFY (mat_h(ispin)%array, mat_p(ispin)%array)
     342              :       END DO
     343              : 
     344              :       IF (forces) THEN
     345              : !$OMP SINGLE
     346              : !$       ALLOCATE (locks(natom*nkind))
     347              : !$OMP END SINGLE
     348              : 
     349              : !$OMP DO
     350              : !$       do lock_num = 1, natom*nkind
     351              : !$          call omp_init_lock(locks(lock_num))
     352              : !$       end do
     353              : !$OMP END DO
     354              :       END IF
     355              : 
     356              :       ! Dynamic schedule to take account of the fact that some slots may be empty
     357              :       ! or contain 1 or more tasks
     358              : !$OMP DO SCHEDULE(DYNAMIC,5)
     359              :       DO slot_num = 1, nl_table_num_slots
     360              :          CALL nl_hash_table_is_null(nl_hash_table, slot_num, is_entry_null)
     361              : 
     362              :          IF (.NOT. is_entry_null) THEN
     363              :             CALL nl_hash_table_get_from_index(nl_hash_table, slot_num, task)
     364              : 
     365              :             is_task_valid = ASSOCIATED(task)
     366              :             DO WHILE (is_task_valid)
     367              : 
     368              :                ikind = task%ikind
     369              :                jkind = task%jkind
     370              :                iatom = task%iatom
     371              :                jatom = task%jatom
     372              :                cell_b(:) = task%cell(:)
     373              : 
     374              :                basis_set_a => basis_set_list(ikind)%gto_basis_set
     375              :                IF (.NOT. ASSOCIATED(basis_set_a)) CYCLE
     376              :                basis_set_b => basis_set_list(jkind)%gto_basis_set
     377              :                IF (.NOT. ASSOCIATED(basis_set_b)) CYCLE
     378              : 
     379              :                IF (nimages > 1) THEN
     380              :                   img = cell_to_index(cell_b(1), cell_b(2), cell_b(3))
     381              :                   CPASSERT(img > 0)
     382              :                ELSE
     383              :                   img = 1
     384              :                END IF
     385              : 
     386              :                DO ispin = 1, nspins
     387              :                   NULLIFY (mat_h(ispin)%array, mat_p(ispin)%array)
     388              : 
     389              :                   found = .FALSE.
     390              :                   IF (iatom <= jatom) THEN
     391              :                      CALL dbcsr_get_block_p(matrix=ksmat(nspins*(img - 1) + ispin)%matrix, &
     392              :                                             row=iatom, col=jatom, &
     393              :                                             BLOCK=mat_h(ispin)%array, found=found)
     394              :                   ELSE
     395              :                      CALL dbcsr_get_block_p(matrix=ksmat(nspins*(img - 1) + ispin)%matrix, &
     396              :                                             row=jatom, col=iatom, &
     397              :                                             BLOCK=mat_h(ispin)%array, found=found)
     398              :                   END IF
     399              :                   CPASSERT(found)
     400              : 
     401              :                   IF (forces) THEN
     402              :                      found = .FALSE.
     403              :                      IF (iatom <= jatom) THEN
     404              :                         CALL dbcsr_get_block_p(matrix=pmat(nspins*(img - 1) + ispin)%matrix, &
     405              :                                                row=iatom, col=jatom, &
     406              :                                                BLOCK=mat_p(ispin)%array, found=found)
     407              :                      ELSE
     408              :                         CALL dbcsr_get_block_p(matrix=pmat(nspins*(img - 1) + ispin)%matrix, &
     409              :                                                row=jatom, col=iatom, &
     410              :                                                BLOCK=mat_p(ispin)%array, found=found)
     411              :                      END IF
     412              :                      CPASSERT(found)
     413              :                   END IF
     414              :                END DO
     415              : 
     416              :                DO kkind = 1, nkind
     417              :                   IF (.NOT. paw_kind(kkind)) CYCLE
     418              : 
     419              :                   iac = ikind + nkind*(kkind - 1)
     420              :                   ibc = jkind + nkind*(kkind - 1)
     421              :                   IF (.NOT. has_intac(iac)) CYCLE
     422              :                   IF (.NOT. has_intac(ibc)) CYCLE
     423              : 
     424              :                   CALL get_alist(my_oce%intac(iac), alist_ac, iatom)
     425              :                   CALL get_alist(my_oce%intac(ibc), alist_bc, jatom)
     426              :                   IF (.NOT. ASSOCIATED(alist_ac)) CYCLE
     427              :                   IF (.NOT. ASSOCIATED(alist_bc)) CYCLE
     428              : 
     429              :                   DO kac = 1, alist_ac%nclist
     430              :                      DO kbc = 1, alist_bc%nclist
     431              :                         IF (alist_ac%clist(kac)%catom /= alist_bc%clist(kbc)%catom) CYCLE
     432              : 
     433              :                         IF (ALL(cell_b + alist_bc%clist(kbc)%cell - alist_ac%clist(kac)%cell == 0)) THEN
     434              :                            n_cont_a = alist_ac%clist(kac)%nsgf_cnt
     435              :                            n_cont_b = alist_bc%clist(kbc)%nsgf_cnt
     436              :                            IF (n_cont_a == 0 .OR. n_cont_b == 0) CYCLE
     437              : 
     438              :                            list_a => alist_ac%clist(kac)%sgf_list
     439              :                            list_b => alist_bc%clist(kbc)%sgf_list
     440              : 
     441              :                            katom = alist_ac%clist(kac)%catom
     442              : 
     443              :                            IF (iatom == katom .AND. ALL(alist_ac%clist(kac)%cell == 0)) THEN
     444              :                               C_coeff_hh_a => alist_ac%clist(kac)%achint
     445              :                               C_coeff_ss_a => alist_ac%clist(kac)%acint
     446              :                               dista = .FALSE.
     447              :                            ELSE
     448              :                               C_coeff_hh_a => alist_ac%clist(kac)%acint
     449              :                               C_coeff_ss_a => alist_ac%clist(kac)%acint
     450              :                               dista = .TRUE.
     451              :                            END IF
     452              : 
     453              :                            IF (jatom == katom .AND. ALL(alist_bc%clist(kbc)%cell == 0)) THEN
     454              :                               C_coeff_hh_b => alist_bc%clist(kbc)%achint
     455              :                               C_coeff_ss_b => alist_bc%clist(kbc)%acint
     456              :                               distb = .FALSE.
     457              :                            ELSE
     458              :                               C_coeff_hh_b => alist_bc%clist(kbc)%acint
     459              :                               C_coeff_ss_b => alist_bc%clist(kbc)%acint
     460              :                               distb = .TRUE.
     461              :                            END IF
     462              : 
     463              :                            rho_at => my_rho_atom(katom)
     464              :                            nsoctot = SIZE(C_coeff_ss_a, 2)
     465              : 
     466              :                            CALL get_rho_atom(rho_atom=rho_at, int_scr_h=int_local_h, int_scr_s=int_local_s)
     467              :                            do_forces = forces .AND. (dista .OR. distb)
     468              :                            ! Use the stored block ordering for both KS and force contractions.
     469              :                            IF (iatom <= jatom) THEN
     470              :                               CALL add_vhxca(mat_h, mat_p, C_coeff_hh_a, C_coeff_hh_b, C_coeff_ss_a, C_coeff_ss_b, &
     471              :                                              int_local_h, int_local_s, nspins, iatom, jatom, nsoctot, factor1, &
     472              :                                              list_a, n_cont_a, list_b, n_cont_b, dista, distb, &
     473              :                                              C_int_h, C_int_s, max_nsgf, coc, a_matrix, p_matrix, &
     474              :                                              do_forces, force_tmp, force_fac)
     475              :                            ELSE
     476              :                               CALL add_vhxca(mat_h, mat_p, C_coeff_hh_b, C_coeff_hh_a, C_coeff_ss_b, C_coeff_ss_a, &
     477              :                                              int_local_h, int_local_s, nspins, jatom, iatom, nsoctot, factor1, &
     478              :                                              list_b, n_cont_b, list_a, n_cont_a, distb, dista, &
     479              :                                              C_int_h, C_int_s, max_nsgf, coc, a_matrix, p_matrix, &
     480              :                                              do_forces, force_tmp, force_fac)
     481              :                               ! Restore the original task ordering of the two endpoint forces.
     482              :                               force_tmp(:, 1:2) = force_tmp(:, 2:1:-1)
     483              :                            END IF
     484              : 
     485              :                            IF (do_forces) THEN
     486              :                               IF (use_virial) THEN
     487              :                                  rac = alist_ac%clist(kac)%rac
     488              :                                  rbc = alist_bc%clist(kbc)%rac
     489              :                               END IF
     490              :                               ia_kind = atom_of_kind(iatom)
     491              :                               ja_kind = atom_of_kind(jatom)
     492              :                               ka_kind = atom_of_kind(katom)
     493              :                               force_tmp = factor2*force_tmp
     494              : !$                            CALL omp_set_lock(locks((ka_kind - 1)*nkind + kkind))
     495              :                               force(kkind)%vhxc_atom(1:3, ka_kind) = force(kkind)%vhxc_atom(1:3, ka_kind) + force_tmp(1:3, 3)
     496              : !$                            CALL omp_unset_lock(locks((ka_kind - 1)*nkind + kkind))
     497              : !$                            CALL omp_set_lock(locks((ia_kind - 1)*nkind + ikind))
     498              :                               force(ikind)%vhxc_atom(1:3, ia_kind) = force(ikind)%vhxc_atom(1:3, ia_kind) + force_tmp(1:3, 1)
     499              : !$                            CALL omp_unset_lock(locks((ia_kind - 1)*nkind + ikind))
     500              : !$                            CALL omp_set_lock(locks((ja_kind - 1)*nkind + jkind))
     501              :                               force(jkind)%vhxc_atom(1:3, ja_kind) = force(jkind)%vhxc_atom(1:3, ja_kind) + force_tmp(1:3, 2)
     502              : !$                            CALL omp_unset_lock(locks((ja_kind - 1)*nkind + jkind))
     503              :                               IF (use_virial) THEN
     504              :                                  CALL virial_pair_force(pv_virial_thread, 1._dp, force_tmp(1:3, 1), rac)
     505              :                                  CALL virial_pair_force(pv_virial_thread, 1._dp, force_tmp(1:3, 2), rbc)
     506              :                               END IF
     507              :                            END IF
     508              :                            EXIT ! search loop over jatom-katom list
     509              :                         END IF
     510              :                      END DO ! kbc
     511              :                   END DO ! kac
     512              : 
     513              :                END DO ! kkind
     514              : 
     515              :                next_task => task%next
     516              :                ! We are done with this task, we can deallocate it
     517              :                DEALLOCATE (task)
     518              :                is_task_valid = ASSOCIATED(next_task)
     519              :                IF (is_task_valid) task => next_task
     520              : 
     521              :             END DO
     522              : 
     523              :          ELSE
     524              :             ! NO KEY/VALUE
     525              :          END IF
     526              :       END DO
     527              : !$OMP END DO
     528              : 
     529              :       DO ispin = 1, nspins
     530              :          NULLIFY (mat_h(ispin)%array, mat_p(ispin)%array)
     531              :       END DO
     532              :       DEALLOCATE (mat_h, mat_p, C_int_h, C_int_s, a_matrix, p_matrix, coc)
     533              : 
     534              :       IF (forces) THEN
     535              :          ! Implicit barrier at end of OMP DO, so locks can be freed
     536              : !$OMP DO
     537              : !$       DO lock_num = 1, natom*nkind
     538              : !$          call omp_destroy_lock(locks(lock_num))
     539              : !$       END DO
     540              : !$OMP END DO
     541              : 
     542              : !$OMP SINGLE
     543              : !$       DEALLOCATE (locks)
     544              : !$OMP END SINGLE NOWAIT
     545              :       END IF
     546              : 
     547              : !$OMP END PARALLEL
     548              : 
     549        41308 :       IF (use_virial) THEN
     550         1742 :          virial%pv_gapw(1:3, 1:3) = virial%pv_gapw(1:3, 1:3) + pv_virial_thread(1:3, 1:3)
     551         1742 :          virial%pv_virial(1:3, 1:3) = virial%pv_virial(1:3, 1:3) + pv_virial_thread(1:3, 1:3)
     552              :       END IF
     553              : 
     554        41308 :       CALL nl_hash_table_release(nl_hash_table)
     555              : 
     556        41308 :       DEALLOCATE (basis_set_list, paw_kind, has_intac)
     557              : 
     558        41308 :       CALL timestop(handle)
     559              : 
     560       165232 :    END SUBROUTINE update_ks_atom
     561              : 
     562              : ! **************************************************************************************************
     563              : !> \brief Add one-center hard-minus-soft KS and coefficient-derivative force contributions.
     564              : !>        Real symmetric one-center potentials allow the same unscaled C*V intermediates
     565              : !>        to be used for KS assembly and forces within each spin.
     566              : !> \param mat_h KS blocks in stored (A <= B) order
     567              : !> \param mat_p density blocks in the same order, used only for forces
     568              : !> \param C_hh_a hard coefficients and derivatives on A
     569              : !> \param C_hh_b hard coefficients and derivatives on B
     570              : !> \param C_ss_a soft coefficients and derivatives on A
     571              : !> \param C_ss_b soft coefficients and derivatives on B
     572              : !> \param int_local_h hard one-center potentials by spin
     573              : !> \param int_local_s soft one-center potentials by spin
     574              : !> \param nspins number of spins
     575              : !> \param ia atom A
     576              : !> \param ja atom B
     577              : !> \param nsp size of the one-center basis
     578              : !> \param factor KS scaling, kept separate from the force scaling
     579              : !> \param lista contracted basis indices on A
     580              : !> \param nconta number of contracted functions on A
     581              : !> \param listb contracted basis indices on B
     582              : !> \param ncontb number of contracted functions on B
     583              : !> \param dista true if A is offsite relative to the expansion center
     584              : !> \param distb true if B is offsite relative to the expansion center
     585              : !> \param work_h workspace for unscaled potential-weighted coefficients
     586              : !> \param work_s workspace for soft or density-weighted coefficients
     587              : !> \param ldwork leading dimension of the coefficient workspaces
     588              : !> \param int_diff workspace for the hard-minus-soft potential
     589              : !> \param a_matrix workspace for the contracted KS block
     590              : !> \param p_matrix workspace for the aligned density block
     591              : !> \param do_forces whether nonzero coefficient-derivative contributions are needed
     592              : !> \param force forces on A, B, and the expansion center
     593              : !> \param force_scaling force scaling by spin
     594              : ! **************************************************************************************************
     595     16565398 :    SUBROUTINE add_vhxca(mat_h, mat_p, C_hh_a, C_hh_b, C_ss_a, C_ss_b, &
     596      8282699 :                         int_local_h, int_local_s, nspins, ia, ja, nsp, factor, &
     597      8282699 :                         lista, nconta, listb, ncontb, dista, distb, &
     598     24848097 :                         work_h, work_s, ldwork, int_diff, a_matrix, p_matrix, &
     599              :                         do_forces, force, force_scaling)
     600              :       TYPE(cp_2d_r_p_type), DIMENSION(:), INTENT(IN)     :: mat_h, mat_p
     601              :       REAL(KIND=dp), DIMENSION(:, :, :), INTENT(IN)      :: C_hh_a, C_hh_b, C_ss_a, C_ss_b
     602              :       TYPE(rho_atom_coeff), DIMENSION(:), INTENT(IN)     :: int_local_h, int_local_s
     603              :       INTEGER, INTENT(IN)                                :: nspins, ia, ja, nsp
     604              :       REAL(KIND=dp), INTENT(IN)                          :: factor
     605              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: lista
     606              :       INTEGER, INTENT(IN)                                :: nconta
     607              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: listb
     608              :       INTEGER, INTENT(IN)                                :: ncontb
     609              :       LOGICAL, INTENT(IN)                                :: dista, distb
     610              :       INTEGER, INTENT(IN)                                :: ldwork
     611              :       REAL(KIND=dp), INTENT(OUT)                         :: work_s(ldwork, nsp), &
     612              :                                                             work_h(ldwork, nsp), int_diff(nsp, nsp)
     613              :       REAL(dp), DIMENSION(:, :), INTENT(OUT)             :: a_matrix, p_matrix
     614              :       LOGICAL, INTENT(IN)                                :: do_forces
     615              :       REAL(dp), DIMENSION(3, 3), INTENT(OUT)             :: force
     616              :       REAL(KIND=dp), DIMENSION(2), INTENT(IN)            :: force_scaling
     617              : 
     618              :       INTEGER                                            :: dir, ispin
     619      8282699 :       REAL(dp), DIMENSION(:, :), POINTER                 :: h_block, int_hard, int_soft, p_block
     620              :       REAL(KIND=dp)                                      :: ieqj, trace
     621              : 
     622      8282699 :       force(:, :) = 0.0_dp
     623              :       ! Factor 2 because only half of the pairs with ia /= ja are considered.
     624      8282699 :       ieqj = 2.0_dp
     625      2448706 :       IF (ia == ja) ieqj = 1.0_dp
     626              : 
     627     16913371 :       DO ispin = 1, nspins
     628      8630672 :          h_block => mat_h(ispin)%array
     629      8630672 :          int_hard => int_local_h(ispin)%r_coef
     630      8630672 :          int_soft => int_local_s(ispin)%r_coef
     631              : 
     632   4984403180 :          IF (dista .AND. distb) int_diff(:, :) = int_hard(1:nsp, 1:nsp) - int_soft(1:nsp, 1:nsp)
     633              : 
     634      8630672 :          IF (distb .AND. .NOT. dista) THEN
     635              :             ! B is offsite: H_ab = (C_a^h V_h - C_a^s V_s) C_b^T.
     636              :             CALL DGEMM('N', 'N', nconta, nsp, nsp, 1.0_dp, C_hh_a(:, :, 1), SIZE(C_hh_a, 1), &
     637       213182 :                        int_hard, SIZE(int_hard, 1), 0.0_dp, work_h, ldwork)
     638              :             CALL DGEMM('N', 'N', nconta, nsp, nsp, -1.0_dp, C_ss_a(:, :, 1), SIZE(C_ss_a, 1), &
     639       213182 :                        int_soft, SIZE(int_soft, 1), 1.0_dp, work_h, ldwork)
     640              :             CALL DGEMM('N', 'T', nconta, ncontb, nsp, factor, work_h, ldwork, &
     641       213182 :                        C_hh_b(:, :, 1), SIZE(C_hh_b, 1), 0.0_dp, a_matrix, SIZE(a_matrix, 1))
     642              :          ELSE
     643      8417490 :             IF (distb) THEN
     644              :                ! Both ends are offsite: C_h = C_s, including their derivatives.
     645              :                CALL DGEMM('N', 'N', ncontb, nsp, nsp, 1.0_dp, C_hh_b(:, :, 1), SIZE(C_hh_b, 1), &
     646      8170750 :                           int_diff, nsp, 0.0_dp, work_h, ldwork)
     647              :             ELSE
     648              :                CALL DGEMM('N', 'N', ncontb, nsp, nsp, 1.0_dp, C_hh_b(:, :, 1), SIZE(C_hh_b, 1), &
     649       246740 :                           int_hard, SIZE(int_hard, 1), 0.0_dp, work_h, ldwork)
     650       246740 :                IF (dista) THEN
     651              :                   CALL DGEMM('N', 'N', ncontb, nsp, nsp, -1.0_dp, C_ss_b(:, :, 1), SIZE(C_ss_b, 1), &
     652       184215 :                              int_soft, SIZE(int_soft, 1), 1.0_dp, work_h, ldwork)
     653              :                ELSE
     654              :                   CALL DGEMM('N', 'N', ncontb, nsp, nsp, 1.0_dp, C_ss_b(:, :, 1), SIZE(C_ss_b, 1), &
     655        62525 :                              int_soft, SIZE(int_soft, 1), 0.0_dp, work_s, ldwork)
     656              :                END IF
     657              :             END IF
     658              :             CALL DGEMM('N', 'T', nconta, ncontb, nsp, factor, C_hh_a(:, :, 1), SIZE(C_hh_a, 1), &
     659      8417490 :                        work_h, ldwork, 0.0_dp, a_matrix, SIZE(a_matrix, 1))
     660      8417490 :             IF (.NOT. dista) THEN
     661              :                CALL DGEMM('N', 'T', nconta, ncontb, nsp, -factor, C_ss_a(:, :, 1), SIZE(C_ss_a, 1), &
     662        62525 :                           work_s, ldwork, 1.0_dp, a_matrix, SIZE(a_matrix, 1))
     663              :             END IF
     664              :          END IF
     665              : 
     666              :          CALL alist_post_align_blk(a_matrix, SIZE(a_matrix, 1), h_block, SIZE(h_block, 1), &
     667      8630672 :                                    lista, nconta, listb, ncontb)
     668              : 
     669      8630672 :          IF (.NOT. do_forces) CYCLE
     670       779039 :          p_block => mat_p(ispin)%array
     671              :          CALL alist_pre_align_blk(p_block, SIZE(p_block, 1), p_matrix, SIZE(p_matrix, 1), &
     672       779039 :                                   lista, nconta, listb, ncontb)
     673              : 
     674              :          ! Onsite coefficient derivatives are zero (see build_oce_matrices).
     675              :          ! The offsite derivative is common to hard and soft coefficients.
     676       779039 :          IF (dista) THEN
     677              :             ! Reuse K_b = C_b^h V_h - C_b^s V_s from KS assembly.
     678              :             CALL DGEMM('N', 'N', nconta, nsp, ncontb, 1.0_dp, p_matrix, SIZE(p_matrix, 1), &
     679       766951 :                        work_h, ldwork, 0.0_dp, work_s, ldwork)
     680              :             ! <(P C_b)^T dC_a, V>_F = <dC_a, P (C_b V)>_F.
     681      3067804 :             DO dir = 2, 4
     682      2300853 :                trace = trace_r_AxB(work_s, ldwork, C_hh_a(:, :, dir), SIZE(C_hh_a, 1), nconta, nsp)
     683      2300853 :                trace = ieqj*trace*force_scaling(ispin)
     684      2300853 :                force(dir - 1, 3) = force(dir - 1, 3) + trace
     685      3067804 :                force(dir - 1, 1) = force(dir - 1, 1) - trace
     686              :             END DO
     687              :          END IF
     688              : 
     689      9061738 :          IF (distb) THEN
     690       766657 :             IF (dista) THEN
     691              :                ! A force used K_b; now form K_a = C_a (V_h - V_s).
     692              :                CALL DGEMM('N', 'N', nconta, nsp, nsp, 1.0_dp, C_hh_a(:, :, 1), SIZE(C_hh_a, 1), &
     693       754569 :                           int_diff, nsp, 0.0_dp, work_h, ldwork)
     694              :             END IF
     695              :             ! For an onsite A, K_a is already available from KS assembly.
     696              :             CALL DGEMM('T', 'N', ncontb, nsp, nconta, 1.0_dp, p_matrix, SIZE(p_matrix, 1), &
     697       766657 :                        work_h, ldwork, 0.0_dp, work_s, ldwork)
     698      3066628 :             DO dir = 2, 4
     699      2299971 :                trace = trace_r_AxB(work_s, ldwork, C_hh_b(:, :, dir), SIZE(C_hh_b, 1), ncontb, nsp)
     700      2299971 :                trace = ieqj*trace*force_scaling(ispin)
     701      2299971 :                force(dir - 1, 3) = force(dir - 1, 3) + trace
     702      3066628 :                force(dir - 1, 2) = force(dir - 1, 2) - trace
     703              :             END DO
     704              :          END IF
     705              :       END DO
     706      8282699 :    END SUBROUTINE add_vhxca
     707              : 
     708              : END MODULE qs_ks_atom
        

Generated by: LCOV version 2.0-1