LCOV - code coverage report
Current view: top level - src - qs_integrate_potential_product.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:2fce0f8) Lines: 143 148 96.6 %
Date: 2024-12-21 06:28:57 Functions: 2 2 100.0 %

          Line data    Source code
       1             : !--------------------------------------------------------------------------------------------------!
       2             : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3             : !   Copyright 2000-2024 CP2K developers group <https://cp2k.org>                                   !
       4             : !                                                                                                  !
       5             : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6             : !--------------------------------------------------------------------------------------------------!
       7             : 
       8             : ! **************************************************************************************************
       9             : !> \brief Build up the plane wave density by collocating the primitive Gaussian
      10             : !>      functions (pgf).
      11             : !> \par History
      12             : !>      Joost VandeVondele (02.2002)
      13             : !>            1) rewrote collocate_pgf for increased accuracy and speed
      14             : !>            2) collocate_core hack for PGI compiler
      15             : !>            3) added multiple grid feature
      16             : !>            4) new way to go over the grid
      17             : !>      Joost VandeVondele (05.2002)
      18             : !>            1) prelim. introduction of the real space grid type
      19             : !>      JGH [30.08.02] multigrid arrays independent from potential
      20             : !>      JGH [17.07.03] distributed real space code
      21             : !>      JGH [23.11.03] refactoring and new loop ordering
      22             : !>      JGH [04.12.03] OpneMP parallelization of main loops
      23             : !>      Joost VandeVondele (12.2003)
      24             : !>           1) modified to compute tau
      25             : !>      Joost removed incremental build feature
      26             : !>      Joost introduced map consistent
      27             : !>      Rewrote grid integration/collocation routines, [Joost VandeVondele,03.2007]
      28             : !>      JGH [26.06.15] modification to allow for k-points
      29             : !> \author Matthias Krack (03.04.2001)
      30             : ! **************************************************************************************************
      31             : MODULE qs_integrate_potential_product
      32             :    USE ao_util,                         ONLY: exp_radius_very_extended
      33             :    USE atomic_kind_types,               ONLY: atomic_kind_type,&
      34             :                                               get_atomic_kind_set
      35             :    USE basis_set_types,                 ONLY: get_gto_basis_set,&
      36             :                                               gto_basis_set_type
      37             :    USE block_p_types,                   ONLY: block_p_type
      38             :    USE cell_types,                      ONLY: cell_type,&
      39             :                                               pbc
      40             :    USE cp_control_types,                ONLY: dft_control_type
      41             :    USE cp_dbcsr_api,                    ONLY: dbcsr_copy,&
      42             :                                               dbcsr_finalize,&
      43             :                                               dbcsr_get_block_p,&
      44             :                                               dbcsr_p_type,&
      45             :                                               dbcsr_type
      46             :    USE cp_dbcsr_operations,             ONLY: dbcsr_deallocate_matrix_set
      47             :    USE gaussian_gridlevels,             ONLY: gridlevel_info_type
      48             :    USE grid_api,                        ONLY: grid_integrate_task_list,&
      49             :                                               integrate_pgf_product
      50             :    USE kinds,                           ONLY: default_string_length,&
      51             :                                               dp
      52             :    USE message_passing,                 ONLY: mp_comm_type
      53             :    USE orbital_pointers,                ONLY: ncoset
      54             :    USE particle_types,                  ONLY: particle_type
      55             :    USE pw_env_types,                    ONLY: pw_env_get,&
      56             :                                               pw_env_type
      57             :    USE pw_types,                        ONLY: pw_r3d_rs_type
      58             :    USE qs_environment_types,            ONLY: get_qs_env,&
      59             :                                               qs_environment_type
      60             :    USE qs_force_types,                  ONLY: qs_force_type
      61             :    USE qs_kind_types,                   ONLY: get_qs_kind,&
      62             :                                               get_qs_kind_set,&
      63             :                                               qs_kind_type
      64             :    USE realspace_grid_types,            ONLY: realspace_grid_desc_p_type,&
      65             :                                               realspace_grid_type
      66             :    USE rs_pw_interface,                 ONLY: potential_pw2rs
      67             :    USE task_list_methods,               ONLY: rs_copy_to_buffer,&
      68             :                                               rs_copy_to_matrices,&
      69             :                                               rs_distribute_matrix,&
      70             :                                               rs_gather_matrices,&
      71             :                                               rs_scatter_matrices
      72             :    USE task_list_types,                 ONLY: atom_pair_type,&
      73             :                                               task_list_type,&
      74             :                                               task_type
      75             :    USE virial_types,                    ONLY: virial_type
      76             : 
      77             : !$ USE OMP_LIB, ONLY: omp_get_max_threads, omp_get_thread_num, omp_get_num_threads
      78             : !$ USE OMP_LIB, ONLY: omp_lock_kind, &
      79             : !$                    omp_init_lock, omp_set_lock, &
      80             : !$                    omp_unset_lock, omp_destroy_lock
      81             : #include "./base/base_uses.f90"
      82             : 
      83             :    IMPLICIT NONE
      84             : 
      85             :    PRIVATE
      86             : 
      87             :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_integrate_potential_product'
      88             : 
      89             : ! *** Public subroutines ***
      90             : ! *** Don't include this routines directly, use the interface to
      91             : ! *** qs_integrate_potential
      92             : 
      93             :    PUBLIC :: integrate_v_rspace
      94             :    PUBLIC :: integrate_v_dbasis
      95             : 
      96             : CONTAINS
      97             : 
      98             : ! **************************************************************************************************
      99             : !> \brief Integrate a potential v_rspace over the derivatives of the basis functions
     100             : !>         < da/dR | V | b > + < a | V | db/dR >
     101             : !>        Adapted from the old version of integrate_v_rspace (ED)
     102             : !> \param v_rspace ...
     103             : !> \param matrix_vhxc_dbasis ...
     104             : !> \param matrix_p ...
     105             : !> \param qs_env ...
     106             : !> \param lambda The atom index.
     107             : ! **************************************************************************************************
     108          84 :    SUBROUTINE integrate_v_dbasis(v_rspace, matrix_vhxc_dbasis, matrix_p, qs_env, lambda)
     109             :       TYPE(pw_r3d_rs_type), INTENT(IN)                   :: v_rspace
     110             :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_vhxc_dbasis
     111             :       TYPE(dbcsr_type), POINTER                          :: matrix_p
     112             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     113             :       INTEGER, INTENT(IN)                                :: lambda
     114             : 
     115             :       CHARACTER(len=*), PARAMETER :: routineN = 'integrate_v_dbasis'
     116             : 
     117             :       INTEGER :: bcol, brow, handle, i, iatom, igrid_level, ikind, ikind_old, ilevel, img, ipair, &
     118             :          ipgf, ipgf_new, iset, iset_new, iset_old, itask, ithread, jatom, jkind, jkind_old, jpgf, &
     119             :          jpgf_new, jset, jset_new, jset_old, maxco, maxpgf, maxset, maxsgf_set, na1, na2, natom, &
     120             :          nb1, nb2, ncoa, ncob, nimages, nkind, nseta, nsetb, nthread, sgfa, sgfb
     121          84 :       INTEGER, ALLOCATABLE, DIMENSION(:, :)              :: block_touched
     122          84 :       INTEGER, DIMENSION(:), POINTER                     :: la_max, la_min, lb_max, lb_min, npgfa, &
     123          84 :                                                             npgfb, nsgfa, nsgfb
     124          84 :       INTEGER, DIMENSION(:, :), POINTER                  :: first_sgfa, first_sgfb
     125             :       LOGICAL :: atom_pair_changed, atom_pair_done, dh_duplicated, distributed_grids, found, &
     126             :          my_compute_tau, new_set_pair_coming, pab_required, scatter, use_subpatch
     127             :       REAL(KIND=dp)                                      :: eps_rho_rspace, f, prefactor, radius, &
     128             :                                                             scalef, zetp
     129             :       REAL(KIND=dp), DIMENSION(3)                        :: force_a, force_b, ra, rab, rab_inv, rb, &
     130             :                                                             rp
     131             :       REAL(KIND=dp), DIMENSION(3, 3)                     :: my_virial_a, my_virial_b
     132          84 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: set_radius_a, set_radius_b
     133          84 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: h_block, hab, p_block, pab, rpgfa, &
     134          84 :                                                             rpgfb, sphi_a, sphi_b, work, zeta, zetb
     135          84 :       REAL(KIND=dp), DIMENSION(:, :, :), POINTER         :: habt, hadb, hdab, pabt, workt
     136          84 :       REAL(kind=dp), DIMENSION(:, :, :, :), POINTER      :: hadbt, hdabt
     137          84 :       TYPE(atom_pair_type), DIMENSION(:), POINTER        :: atom_pair_recv, atom_pair_send
     138          84 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
     139          84 :       TYPE(block_p_type), ALLOCATABLE, DIMENSION(:)      :: vhxc_block
     140             :       TYPE(cell_type), POINTER                           :: cell
     141          84 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: deltap
     142             :       TYPE(dft_control_type), POINTER                    :: dft_control
     143             :       TYPE(gridlevel_info_type), POINTER                 :: gridlevel_info
     144             :       TYPE(gto_basis_set_type), POINTER                  :: orb_basis_set
     145             :       TYPE(mp_comm_type)                                 :: group
     146          84 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     147             :       TYPE(pw_env_type), POINTER                         :: pw_env
     148          84 :       TYPE(qs_force_type), DIMENSION(:), POINTER         :: force
     149          84 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     150             :       TYPE(realspace_grid_desc_p_type), DIMENSION(:), &
     151          84 :          POINTER                                         :: rs_descs
     152          84 :       TYPE(realspace_grid_type), DIMENSION(:), POINTER   :: rs_rho
     153             :       TYPE(task_list_type), POINTER                      :: task_list
     154          84 :       TYPE(task_type), DIMENSION(:), POINTER             :: tasks
     155             : 
     156          84 :       CALL timeset(routineN, handle)
     157          84 :       NULLIFY (pw_env)
     158             : 
     159             :       ! get the task lists
     160          84 :       CALL get_qs_env(qs_env=qs_env, task_list=task_list)
     161          84 :       CPASSERT(ASSOCIATED(task_list))
     162             : 
     163             :       ! the information on the grids is provided through pw_env
     164             :       ! pw_env has to be the parent env for the potential grid (input)
     165             :       ! there is an option to provide an external grid
     166          84 :       CALL get_qs_env(qs_env=qs_env, pw_env=pw_env)
     167             : 
     168             :       ! *** assign from pw_env
     169          84 :       gridlevel_info => pw_env%gridlevel_info
     170             : 
     171             :       ! get all the general information on the system we are working on
     172             :       CALL get_qs_env(qs_env=qs_env, &
     173             :                       atomic_kind_set=atomic_kind_set, &
     174             :                       qs_kind_set=qs_kind_set, &
     175             :                       cell=cell, &
     176             :                       natom=natom, &
     177             :                       dft_control=dft_control, &
     178          84 :                       particle_set=particle_set)
     179             : 
     180             :       ! GAPW not implemented here
     181          84 :       CPASSERT(.NOT. dft_control%qs_control%gapw)
     182             : 
     183             :       ! *** set up the rs multi-grids
     184          84 :       CPASSERT(ASSOCIATED(pw_env))
     185          84 :       CALL pw_env_get(pw_env, rs_descs=rs_descs, rs_grids=rs_rho)
     186         258 :       DO igrid_level = 1, gridlevel_info%ngrid_levels
     187         258 :          distributed_grids = rs_rho(igrid_level)%desc%distributed
     188             :       END DO
     189             :       ! get mpi group from rs_rho
     190          84 :       group = rs_rho(1)%desc%group
     191             : 
     192             :       ! transform the potential on the rs_multigrids
     193          84 :       CALL potential_pw2rs(rs_rho, v_rspace, pw_env)
     194             : 
     195          84 :       nkind = SIZE(qs_kind_set)
     196             : 
     197             :       CALL get_qs_kind_set(qs_kind_set=qs_kind_set, &
     198             :                            maxco=maxco, &
     199             :                            maxsgf_set=maxsgf_set, &
     200          84 :                            basis_type="ORB")
     201             : 
     202             :       ! short cuts to task list variables
     203          84 :       tasks => task_list%tasks
     204          84 :       atom_pair_send => task_list%atom_pair_send
     205          84 :       atom_pair_recv => task_list%atom_pair_recv
     206             : 
     207             :       ! needs to be consistent with rho_rspace
     208          84 :       eps_rho_rspace = dft_control%qs_control%eps_rho_rspace
     209             : 
     210             :       !   *** Initialize working density matrix ***
     211             :       ! distributed rs grids require a matrix that will be changed
     212             :       ! whereas this is not the case for replicated grids
     213         336 :       ALLOCATE (deltap(dft_control%nimages))
     214          84 :       IF (distributed_grids) THEN
     215             :          ! this matrix has no strict sparsity pattern in parallel
     216             :          ! deltap%sparsity_id=-1
     217           0 :          CALL dbcsr_copy(deltap(1)%matrix, matrix_p, name="DeltaP")
     218             :       ELSE
     219          84 :          deltap(1)%matrix => matrix_p
     220             :       END IF
     221          84 :       nthread = 1
     222          84 : !$    nthread = omp_get_max_threads()
     223             : 
     224             :       !   *** Allocate work storage ***
     225          84 :       NULLIFY (pabt, habt, workt)
     226         420 :       ALLOCATE (habt(maxco, maxco, 0:nthread))
     227         420 :       ALLOCATE (workt(maxco, maxsgf_set, 0:nthread))
     228         420 :       ALLOCATE (hdabt(3, maxco, maxco, 0:nthread))
     229         336 :       ALLOCATE (hadbt(3, maxco, maxco, 0:nthread))
     230         336 :       ALLOCATE (pabt(maxco, maxco, 0:nthread))
     231             : 
     232          84 :       IF (distributed_grids) THEN
     233             :          CALL rs_distribute_matrix(rs_descs, deltap, atom_pair_send, atom_pair_recv, &
     234           0 :                                    nimages, scatter=.TRUE.)
     235             :       END IF
     236             : 
     237             : !$OMP PARALLEL DEFAULT(NONE), &
     238             : !$OMP SHARED(workt,habt,hdabt,hadbt,pabt,tasks,particle_set,natom,maxset), &
     239             : !$OMP SHARED(maxpgf,matrix_vhxc_dbasis,deltap), &
     240             : !$OMP SHARED(pab_required,ncoset,rs_rho,my_compute_tau), &
     241             : !$OMP SHARED(eps_rho_rspace,force,cell), &
     242             : !$OMP SHARED(gridlevel_info,task_list,block_touched,nthread,qs_kind_set), &
     243             : !$OMP SHARED(nimages,lambda, dh_duplicated), &
     244             : !$OMP PRIVATE(ithread,work,hab,hdab,hadb,pab,iset_old,jset_old), &
     245             : !$OMP PRIVATE(ikind_old,jkind_old,iatom,jatom,iset,jset,ikind,jkind,ilevel,ipgf,jpgf), &
     246             : !$OMP PRIVATE(img,brow,bcol,orb_basis_set,first_sgfa,la_max,la_min,npgfa,nseta,nsgfa), &
     247             : !$OMP PRIVATE(rpgfa,set_radius_a,sphi_a,zeta,first_sgfb,lb_max,lb_min,npgfb), &
     248             : !$OMP PRIVATE(nsetb,nsgfb,rpgfb,set_radius_b,sphi_b,zetb,found), &
     249             : !$OMP PRIVATE(force_a,force_b,my_virial_a,my_virial_b,atom_pair_changed,h_block, vhxc_block), &
     250             : !$OMP PRIVATE(p_block,ncoa,sgfa,ncob,sgfb,rab,ra,rb,rp,zetp,f,prefactor,radius,igrid_level), &
     251             : !$OMP PRIVATE(na1,na2,nb1,nb2,use_subpatch,rab_inv,new_set_pair_coming,atom_pair_done), &
     252             : !$OMP PRIVATE(iset_new,jset_new,ipgf_new,jpgf_new,scalef), &
     253          84 : !$OMP PRIVATE(itask)
     254             : 
     255             :       IF (.NOT. ALLOCATED(vhxc_block)) ALLOCATE (vhxc_block(3))
     256             : 
     257             :       ithread = 0
     258             : !$    ithread = omp_get_thread_num()
     259             :       work => workt(:, :, ithread)
     260             :       hab => habt(:, :, ithread)
     261             :       pab => pabt(:, :, ithread)
     262             :       hdab => hdabt(:, :, :, ithread)
     263             :       hadb => hadbt(:, :, :, ithread)
     264             : 
     265             :       iset_old = -1; jset_old = -1
     266             :       ikind_old = -1; jkind_old = -1
     267             : 
     268             :       ! Here we loop over gridlevels first, finalising the matrix after each grid level is
     269             :       ! completed.  On each grid level, we loop over atom pairs, which will only access
     270             :       ! a single block of each matrix, so with OpenMP, each matrix block is only touched
     271             :       ! by a single thread for each grid level
     272             :       loop_gridlevels: DO igrid_level = 1, gridlevel_info%ngrid_levels
     273             : !$OMP BARRIER
     274             : !$OMP DO schedule (dynamic, MAX(1,task_list%npairs(igrid_level)/(nthread*50)))
     275             :          loop_pairs: DO ipair = 1, task_list%npairs(igrid_level)
     276             :          loop_tasks: DO itask = task_list%taskstart(ipair, igrid_level), task_list%taskstop(ipair, igrid_level)
     277             :             ilevel = tasks(itask)%grid_level
     278             :             img = tasks(itask)%image
     279             :             iatom = tasks(itask)%iatom
     280             :             jatom = tasks(itask)%jatom
     281             :             iset = tasks(itask)%iset
     282             :             jset = tasks(itask)%jset
     283             :             ipgf = tasks(itask)%ipgf
     284             :             jpgf = tasks(itask)%jpgf
     285             : 
     286             :             ! At the start of a block of tasks, get atom data (and kind data, if needed)
     287             :             IF (itask .EQ. task_list%taskstart(ipair, igrid_level)) THEN
     288             : 
     289             :                ikind = particle_set(iatom)%atomic_kind%kind_number
     290             :                jkind = particle_set(jatom)%atomic_kind%kind_number
     291             : 
     292             :                ra(:) = pbc(particle_set(iatom)%r, cell)
     293             : 
     294             :                IF (iatom <= jatom) THEN
     295             :                   brow = iatom
     296             :                   bcol = jatom
     297             :                ELSE
     298             :                   brow = jatom
     299             :                   bcol = iatom
     300             :                END IF
     301             : 
     302             :                IF (ikind .NE. ikind_old) THEN
     303             :                   CALL get_qs_kind(qs_kind_set(ikind), &
     304             :                                    basis_set=orb_basis_set, basis_type="ORB")
     305             : 
     306             :                   CALL get_gto_basis_set(gto_basis_set=orb_basis_set, &
     307             :                                          first_sgf=first_sgfa, &
     308             :                                          lmax=la_max, &
     309             :                                          lmin=la_min, &
     310             :                                          npgf=npgfa, &
     311             :                                          nset=nseta, &
     312             :                                          nsgf_set=nsgfa, &
     313             :                                          pgf_radius=rpgfa, &
     314             :                                          set_radius=set_radius_a, &
     315             :                                          sphi=sphi_a, &
     316             :                                          zet=zeta)
     317             :                END IF
     318             : 
     319             :                IF (jkind .NE. jkind_old) THEN
     320             :                   CALL get_qs_kind(qs_kind_set(jkind), &
     321             :                                    basis_set=orb_basis_set, basis_type="ORB")
     322             :                   CALL get_gto_basis_set(gto_basis_set=orb_basis_set, &
     323             :                                          first_sgf=first_sgfb, &
     324             :                                          lmax=lb_max, &
     325             :                                          lmin=lb_min, &
     326             :                                          npgf=npgfb, &
     327             :                                          nset=nsetb, &
     328             :                                          nsgf_set=nsgfb, &
     329             :                                          pgf_radius=rpgfb, &
     330             :                                          set_radius=set_radius_b, &
     331             :                                          sphi=sphi_b, &
     332             :                                          zet=zetb)
     333             : 
     334             :                END IF
     335             : 
     336             :                DO i = 1, 3
     337             :                   NULLIFY (vhxc_block(i)%block)
     338             :                   CALL dbcsr_get_block_p(matrix_vhxc_dbasis(i)%matrix, brow, bcol, vhxc_block(i)%block, found)
     339             :                   CPASSERT(found)
     340             :                END DO
     341             : 
     342             :                CALL dbcsr_get_block_p(matrix=deltap(img)%matrix, &
     343             :                                       row=brow, col=bcol, BLOCK=p_block, found=found)
     344             :                CPASSERT(found)
     345             : 
     346             :                ikind_old = ikind
     347             :                jkind_old = jkind
     348             : 
     349             :                atom_pair_changed = .TRUE.
     350             : 
     351             :             ELSE
     352             : 
     353             :                atom_pair_changed = .FALSE.
     354             : 
     355             :             END IF
     356             : 
     357             :             IF (atom_pair_changed .OR. iset_old .NE. iset .OR. jset_old .NE. jset) THEN
     358             : 
     359             :                ncoa = npgfa(iset)*ncoset(la_max(iset))
     360             :                sgfa = first_sgfa(1, iset)
     361             :                ncob = npgfb(jset)*ncoset(lb_max(jset))
     362             :                sgfb = first_sgfb(1, jset)
     363             : 
     364             :                IF (iatom <= jatom) THEN
     365             :                   work(1:ncoa, 1:nsgfb(jset)) = MATMUL(sphi_a(1:ncoa, sgfa:sgfa + nsgfa(iset) - 1), &
     366             :                                                        p_block(sgfa:sgfa + nsgfa(iset) - 1, sgfb:sgfb + nsgfb(jset) - 1))
     367             :                   pab(1:ncoa, 1:ncob) = MATMUL(work(1:ncoa, 1:nsgfb(jset)), TRANSPOSE(sphi_b(1:ncob, sgfb:sgfb + nsgfb(jset) - 1)))
     368             :                ELSE
     369             :                   work(1:ncob, 1:nsgfa(iset)) = MATMUL(sphi_b(1:ncob, sgfb:sgfb + nsgfb(jset) - 1), &
     370             :                                                        p_block(sgfb:sgfb + nsgfb(jset) - 1, sgfa:sgfa + nsgfa(iset) - 1))
     371             :                   pab(1:ncob, 1:ncoa) = MATMUL(work(1:ncob, 1:nsgfa(iset)), TRANSPOSE(sphi_a(1:ncoa, sgfa:sgfa + nsgfa(iset) - 1)))
     372             :                END IF
     373             : 
     374             :                IF (iatom <= jatom) THEN
     375             :                   hab(1:ncoa, 1:ncob) = 0._dp
     376             :                   hdab(:, 1:ncoa, 1:ncob) = 0._dp
     377             :                   hadb(:, 1:ncoa, 1:ncob) = 0._dp
     378             :                ELSE
     379             :                   hab(1:ncob, 1:ncoa) = 0._dp
     380             :                   hdab(:, 1:ncob, 1:ncoa) = 0._dp
     381             :                   hadb(:, 1:ncob, 1:ncoa) = 0._dp
     382             :                END IF
     383             : 
     384             :                iset_old = iset
     385             :                jset_old = jset
     386             : 
     387             :             END IF
     388             : 
     389             :             rab = tasks(itask)%rab
     390             :             rb(:) = ra(:) + rab(:)
     391             :             zetp = zeta(ipgf, iset) + zetb(jpgf, jset)
     392             : 
     393             :             f = zetb(jpgf, jset)/zetp
     394             :             rp(:) = ra(:) + f*rab(:)
     395             :             prefactor = EXP(-zeta(ipgf, iset)*f*DOT_PRODUCT(rab, rab))
     396             :             radius = exp_radius_very_extended(la_min=la_min(iset), la_max=la_max(iset), &
     397             :                                               lb_min=lb_min(jset), lb_max=lb_max(jset), &
     398             :                                               ra=ra, rb=rb, rp=rp, &
     399             :                                               zetp=zetp, eps=eps_rho_rspace, &
     400             :                                               prefactor=prefactor, cutoff=1.0_dp)
     401             : 
     402             :             na1 = (ipgf - 1)*ncoset(la_max(iset)) + 1
     403             :             na2 = ipgf*ncoset(la_max(iset))
     404             :             nb1 = (jpgf - 1)*ncoset(lb_max(jset)) + 1
     405             :             nb2 = jpgf*ncoset(lb_max(jset))
     406             : 
     407             :             ! check whether we need to use fawzi's generalised collocation scheme
     408             :             IF (rs_rho(igrid_level)%desc%distributed) THEN
     409             :                !tasks(4,:) is 0 for replicated, 1 for distributed 2 for exceptional distributed tasks
     410             :                IF (tasks(itask)%dist_type .EQ. 2) THEN
     411             :                   use_subpatch = .TRUE.
     412             :                ELSE
     413             :                   use_subpatch = .FALSE.
     414             :                END IF
     415             :             ELSE
     416             :                use_subpatch = .FALSE.
     417             :             END IF
     418             : 
     419             :             IF (iatom <= jatom) THEN
     420             :                IF (iatom == lambda) &
     421             :                   CALL integrate_pgf_product( &
     422             :                   la_max(iset), zeta(ipgf, iset), la_min(iset), &
     423             :                   lb_max(jset), zetb(jpgf, jset), lb_min(jset), &
     424             :                   ra, rab, rs_rho(igrid_level), &
     425             :                   hab, o1=na1 - 1, o2=nb1 - 1, &
     426             :                   radius=radius, &
     427             :                   calculate_forces=.TRUE., &
     428             :                   compute_tau=.FALSE., &
     429             :                   use_subpatch=use_subpatch, subpatch_pattern=tasks(itask)%subpatch_pattern, &
     430             :                   hdab=hdab, pab=pab)
     431             :                IF (jatom == lambda) &
     432             :                   CALL integrate_pgf_product( &
     433             :                   la_max(iset), zeta(ipgf, iset), la_min(iset), &
     434             :                   lb_max(jset), zetb(jpgf, jset), lb_min(jset), &
     435             :                   ra, rab, rs_rho(igrid_level), &
     436             :                   hab, o1=na1 - 1, o2=nb1 - 1, &
     437             :                   radius=radius, &
     438             :                   calculate_forces=.TRUE., &
     439             :                   compute_tau=.FALSE., &
     440             :                   use_subpatch=use_subpatch, subpatch_pattern=tasks(itask)%subpatch_pattern, &
     441             :                   hadb=hadb, pab=pab)
     442             :             ELSE
     443             :                rab_inv = -rab
     444             :                IF (iatom == lambda) &
     445             :                   CALL integrate_pgf_product( &
     446             :                   lb_max(jset), zetb(jpgf, jset), lb_min(jset), &
     447             :                   la_max(iset), zeta(ipgf, iset), la_min(iset), &
     448             :                   rb, rab_inv, rs_rho(igrid_level), &
     449             :                   hab, o1=nb1 - 1, o2=na1 - 1, &
     450             :                   radius=radius, &
     451             :                   calculate_forces=.TRUE., &
     452             :                   force_a=force_b, force_b=force_a, &
     453             :                   compute_tau=.FALSE., &
     454             :                   use_subpatch=use_subpatch, subpatch_pattern=tasks(itask)%subpatch_pattern, &
     455             :                   hadb=hadb, pab=pab)
     456             :                IF (jatom == lambda) &
     457             :                   CALL integrate_pgf_product( &
     458             :                   lb_max(jset), zetb(jpgf, jset), lb_min(jset), &
     459             :                   la_max(iset), zeta(ipgf, iset), la_min(iset), &
     460             :                   rb, rab_inv, rs_rho(igrid_level), &
     461             :                   hab, o1=nb1 - 1, o2=na1 - 1, &
     462             :                   radius=radius, &
     463             :                   calculate_forces=.TRUE., &
     464             :                   force_a=force_b, force_b=force_a, &
     465             :                   compute_tau=.FALSE., &
     466             :                   use_subpatch=use_subpatch, subpatch_pattern=tasks(itask)%subpatch_pattern, &
     467             :                   hdab=hdab, pab=pab)
     468             :             END IF
     469             : 
     470             :             new_set_pair_coming = .FALSE.
     471             :             atom_pair_done = .FALSE.
     472             :             IF (itask < task_list%taskstop(ipair, igrid_level)) THEN
     473             :                ilevel = tasks(itask + 1)%grid_level
     474             :                img = tasks(itask + 1)%image
     475             :                iatom = tasks(itask + 1)%iatom
     476             :                jatom = tasks(itask + 1)%jatom
     477             :                iset_new = tasks(itask + 1)%iset
     478             :                jset_new = tasks(itask + 1)%jset
     479             :                ipgf_new = tasks(itask + 1)%ipgf
     480             :                jpgf_new = tasks(itask + 1)%jpgf
     481             :                IF (iset_new .NE. iset .OR. jset_new .NE. jset) THEN
     482             :                   new_set_pair_coming = .TRUE.
     483             :                END IF
     484             :             ELSE
     485             :                ! do not forget the last block
     486             :                new_set_pair_coming = .TRUE.
     487             :                atom_pair_done = .TRUE.
     488             :             END IF
     489             : 
     490             :             IF (new_set_pair_coming) THEN
     491             : 
     492             :                DO i = 1, 3
     493             :                   hdab(i, :, :) = hdab(i, :, :) + hadb(i, :, :)
     494             :                   IF (iatom <= jatom) THEN
     495             :                      work(1:ncoa, 1:nsgfb(jset)) = MATMUL(hdab(i, 1:ncoa, 1:ncob), sphi_b(1:ncob, sgfb:sgfb + nsgfb(jset) - 1))
     496             :                      vhxc_block(i)%block(sgfa:sgfa + nsgfa(iset) - 1, sgfb:sgfb + nsgfb(jset) - 1) = &
     497             :                         vhxc_block(i)%block(sgfa:sgfa + nsgfa(iset) - 1, sgfb:sgfb + nsgfb(jset) - 1) + &
     498             :                         MATMUL(TRANSPOSE(sphi_a(1:ncoa, sgfa:sgfa + nsgfa(iset) - 1)), work(1:ncoa, 1:nsgfb(jset)))
     499             :                   ELSE
     500             :                      work(1:ncob, 1:nsgfa(iset)) = MATMUL(hdab(i, 1:ncob, 1:ncoa), sphi_a(1:ncoa, sgfa:sgfa + nsgfa(iset) - 1))
     501             :                      vhxc_block(i)%block(sgfb:sgfb + nsgfb(jset) - 1, sgfa:sgfa + nsgfa(iset) - 1) = &
     502             :                         vhxc_block(i)%block(sgfb:sgfb + nsgfb(jset) - 1, sgfa:sgfa + nsgfa(iset) - 1) + &
     503             :                         MATMUL(TRANSPOSE(sphi_b(1:ncob, sgfb:sgfb + nsgfb(jset) - 1)), work(1:ncob, 1:nsgfa(iset)))
     504             :                   END IF
     505             :                END DO
     506             :             END IF  ! new_set_pair_coming
     507             : 
     508             :          END DO loop_tasks
     509             :          END DO loop_pairs
     510             : !$OMP END DO
     511             : 
     512             :          DO i = 1, 3
     513             :             CALL dbcsr_finalize(matrix_vhxc_dbasis(i)%matrix)
     514             :          END DO
     515             : 
     516             :       END DO loop_gridlevels
     517             : 
     518             : !$OMP END PARALLEL
     519             : 
     520          84 :       IF (distributed_grids) THEN
     521             :          ! Reconstruct H matrix if using distributed RS grids
     522             :          ! note send and recv direction reversed WRT collocate
     523           0 :          scatter = .FALSE.
     524             :          CALL rs_distribute_matrix(rs_descs, matrix_vhxc_dbasis, atom_pair_recv, atom_pair_send, &
     525           0 :                                    dft_control%nimages, scatter=.FALSE.)
     526             :       END IF
     527             : 
     528             :       IF (distributed_grids) THEN
     529           0 :          CALL dbcsr_deallocate_matrix_set(deltap)
     530             :       ELSE
     531         168 :          DO img = 1, dft_control%nimages
     532         168 :             NULLIFY (deltap(img)%matrix)
     533             :          END DO
     534          84 :          DEALLOCATE (deltap)
     535             :       END IF
     536             : 
     537          84 :       DEALLOCATE (pabt, habt, workt, hdabt, hadbt)
     538             : 
     539          84 :       CALL timestop(handle)
     540         252 :    END SUBROUTINE integrate_v_dbasis
     541             : 
     542             : ! **************************************************************************************************
     543             : !> \brief computes matrix elements corresponding to a given potential
     544             : !> \param v_rspace ...
     545             : !> \param hmat ...
     546             : !> \param hmat_kp ...
     547             : !> \param pmat ...
     548             : !> \param pmat_kp ...
     549             : !> \param qs_env ...
     550             : !> \param calculate_forces ...
     551             : !> \param force_adm optional scaling of force
     552             : !> \param compute_tau ...
     553             : !> \param gapw ...
     554             : !> \param basis_type ...
     555             : !> \param pw_env_external ...
     556             : !> \param task_list_external ...
     557             : !> \par History
     558             : !>      IAB (29-Apr-2010): Added OpenMP parallelisation to task loop
     559             : !>                         (c) The Numerical Algorithms Group (NAG) Ltd, 2010 on behalf of the HECToR project
     560             : !>      Some refactoring, get priorities for options correct (JGH, 04.2014)
     561             : !>      Added options to allow for k-points
     562             : !>      For a smooth transition we allow for old and new (vector) matrices (hmat, pmat) (JGH, 06.2015)
     563             : !> \note
     564             : !>     integrates a given potential (or other object on a real
     565             : !>     space grid) = v_rspace using a multi grid technique (mgrid_*)
     566             : !>     over the basis set producing a number for every element of h
     567             : !>     (should have the same sparsity structure of S)
     568             : !>     additional screening is available using the magnitude of the
     569             : !>     elements in p (? I'm not sure this is a very good idea)
     570             : !>     this argument is optional
     571             : !>     derivatives of these matrix elements with respect to the ionic
     572             : !>     coordinates can be computed as well
     573             : ! **************************************************************************************************
     574      180813 :    SUBROUTINE integrate_v_rspace(v_rspace, hmat, hmat_kp, pmat, pmat_kp, &
     575             :                                  qs_env, calculate_forces, force_adm, &
     576             :                                  compute_tau, gapw, basis_type, pw_env_external, task_list_external)
     577             : 
     578             :       TYPE(pw_r3d_rs_type), INTENT(IN)                   :: v_rspace
     579             :       TYPE(dbcsr_p_type), INTENT(INOUT), OPTIONAL        :: hmat
     580             :       TYPE(dbcsr_p_type), DIMENSION(:), OPTIONAL, &
     581             :          POINTER                                         :: hmat_kp
     582             :       TYPE(dbcsr_p_type), INTENT(IN), OPTIONAL           :: pmat
     583             :       TYPE(dbcsr_p_type), DIMENSION(:), OPTIONAL, &
     584             :          POINTER                                         :: pmat_kp
     585             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     586             :       LOGICAL, INTENT(IN)                                :: calculate_forces
     587             :       REAL(KIND=dp), INTENT(IN), OPTIONAL                :: force_adm
     588             :       LOGICAL, INTENT(IN), OPTIONAL                      :: compute_tau, gapw
     589             :       CHARACTER(len=*), INTENT(IN), OPTIONAL             :: basis_type
     590             :       TYPE(pw_env_type), OPTIONAL, POINTER               :: pw_env_external
     591             :       TYPE(task_list_type), OPTIONAL, POINTER            :: task_list_external
     592             : 
     593             :       CHARACTER(len=*), PARAMETER :: routineN = 'integrate_v_rspace'
     594             : 
     595             :       CHARACTER(len=default_string_length)               :: my_basis_type
     596             :       INTEGER                                            :: atom_a, handle, iatom, igrid_level, &
     597             :                                                             ikind, img, maxco, maxsgf_set, natoms, &
     598             :                                                             nimages, nkind
     599      180813 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: atom_of_kind, kind_of
     600             :       LOGICAL                                            :: calculate_virial, distributed_grids, &
     601             :                                                             do_kp, my_compute_tau, my_gapw, &
     602             :                                                             pab_required
     603             :       REAL(KIND=dp)                                      :: admm_scal_fac
     604      180813 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: forces_array
     605             :       REAL(KIND=dp), DIMENSION(3, 3)                     :: virial_matrix
     606      180813 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
     607             :       TYPE(cell_type), POINTER                           :: cell
     608      180813 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: deltap, dhmat
     609             :       TYPE(dft_control_type), POINTER                    :: dft_control
     610             :       TYPE(gridlevel_info_type), POINTER                 :: gridlevel_info
     611             :       TYPE(mp_comm_type)                                 :: group
     612      180813 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     613             :       TYPE(pw_env_type), POINTER                         :: pw_env
     614      180813 :       TYPE(qs_force_type), DIMENSION(:), POINTER         :: force
     615      180813 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     616      180813 :       TYPE(realspace_grid_type), DIMENSION(:), POINTER   :: rs_v
     617             :       TYPE(task_list_type), POINTER                      :: task_list, task_list_soft
     618             :       TYPE(virial_type), POINTER                         :: virial
     619             : 
     620      180813 :       CALL timeset(routineN, handle)
     621             : 
     622             :       ! we test here if the provided operator matrices are consistent
     623      180813 :       CPASSERT(PRESENT(hmat) .OR. PRESENT(hmat_kp))
     624      180813 :       do_kp = .FALSE.
     625      180813 :       IF (PRESENT(hmat_kp)) do_kp = .TRUE.
     626      180813 :       IF (PRESENT(pmat)) THEN
     627       32028 :          CPASSERT(PRESENT(hmat))
     628      148785 :       ELSE IF (PRESENT(pmat_kp)) THEN
     629      120565 :          CPASSERT(PRESENT(hmat_kp))
     630             :       END IF
     631             : 
     632      180813 :       NULLIFY (pw_env)
     633             : 
     634             :       ! this routine works in two modes:
     635             :       ! normal mode : <a| V | b>
     636             :       ! tau mode    : < nabla a| V | nabla b>
     637      180813 :       my_compute_tau = .FALSE.
     638      180813 :       IF (PRESENT(compute_tau)) my_compute_tau = compute_tau
     639             : 
     640             :       ! this sets the basis set to be used. GAPW(==soft basis) overwrites basis_type
     641             :       ! default is "ORB"
     642      180813 :       my_gapw = .FALSE.
     643      180813 :       IF (PRESENT(gapw)) my_gapw = gapw
     644      180813 :       IF (PRESENT(basis_type)) THEN
     645       12350 :          my_basis_type = basis_type
     646             :       ELSE
     647      168463 :          my_basis_type = "ORB"
     648             :       END IF
     649             : 
     650             :       ! get the task lists
     651             :       ! task lists have to be in sync with basis sets
     652             :       ! there is an option to provide the task list from outside (not through qs_env)
     653             :       ! outside option has highest priority
     654             :       CALL get_qs_env(qs_env=qs_env, &
     655             :                       task_list=task_list, &
     656      180813 :                       task_list_soft=task_list_soft)
     657      180813 :       IF (.NOT. my_basis_type == "ORB") THEN
     658       11750 :          CPASSERT(PRESENT(task_list_external))
     659             :       END IF
     660      180813 :       IF (my_gapw) task_list => task_list_soft
     661      180813 :       IF (PRESENT(task_list_external)) task_list => task_list_external
     662      180813 :       CPASSERT(ASSOCIATED(task_list))
     663             : 
     664             :       ! the information on the grids is provided through pw_env
     665             :       ! pw_env has to be the parent env for the potential grid (input)
     666             :       ! there is an option to provide an external grid
     667      180813 :       CALL get_qs_env(qs_env=qs_env, pw_env=pw_env)
     668      180813 :       IF (PRESENT(pw_env_external)) pw_env => pw_env_external
     669             : 
     670             :       ! get all the general information on the system we are working on
     671             :       CALL get_qs_env(qs_env=qs_env, &
     672             :                       atomic_kind_set=atomic_kind_set, &
     673             :                       qs_kind_set=qs_kind_set, &
     674             :                       cell=cell, &
     675             :                       natom=natoms, &
     676             :                       dft_control=dft_control, &
     677             :                       particle_set=particle_set, &
     678             :                       force=force, &
     679      180813 :                       virial=virial)
     680             : 
     681      180813 :       admm_scal_fac = 1.0_dp
     682      180813 :       IF (PRESENT(force_adm)) admm_scal_fac = force_adm
     683             : 
     684      180813 :       CPASSERT(ASSOCIATED(pw_env))
     685      180813 :       CALL pw_env_get(pw_env, rs_grids=rs_v)
     686             : 
     687             :       ! get mpi group from rs_v
     688      180813 :       group = rs_v(1)%desc%group
     689             : 
     690             :       ! assign from pw_env
     691      180813 :       gridlevel_info => pw_env%gridlevel_info
     692             : 
     693             :       ! transform the potential on the rs_multigrids
     694      180813 :       CALL potential_pw2rs(rs_v, v_rspace, pw_env)
     695             : 
     696      180813 :       nimages = dft_control%nimages
     697      180813 :       IF (nimages > 1) THEN
     698        1378 :          CPASSERT(do_kp)
     699             :       END IF
     700      180813 :       nkind = SIZE(qs_kind_set)
     701      180813 :       calculate_virial = virial%pv_availability .AND. (.NOT. virial%pv_numer) .AND. calculate_forces
     702      180813 :       pab_required = (PRESENT(pmat) .OR. PRESENT(pmat_kp)) .AND. calculate_forces
     703             : 
     704             :       CALL get_qs_kind_set(qs_kind_set=qs_kind_set, &
     705             :                            maxco=maxco, &
     706             :                            maxsgf_set=maxsgf_set, &
     707      180813 :                            basis_type=my_basis_type)
     708             : 
     709      180813 :       distributed_grids = .FALSE.
     710      896165 :       DO igrid_level = 1, gridlevel_info%ngrid_levels
     711      896165 :          IF (rs_v(igrid_level)%desc%distributed) THEN
     712         230 :             distributed_grids = .TRUE.
     713             :          END IF
     714             :       END DO
     715             : 
     716      542439 :       ALLOCATE (forces_array(3, natoms))
     717             : 
     718      180813 :       IF (pab_required) THEN
     719             :          ! initialize the working pmat structures
     720      104474 :          ALLOCATE (deltap(nimages))
     721       22757 :          IF (do_kp) THEN
     722       26248 :             DO img = 1, nimages
     723       26248 :                deltap(img)%matrix => pmat_kp(img)%matrix
     724             :             END DO
     725             :          ELSE
     726       16356 :             deltap(1)%matrix => pmat%matrix
     727             :          END IF
     728             : 
     729             :          ! Distribute matrix blocks.
     730       22757 :          IF (distributed_grids) THEN
     731          36 :             CALL rs_scatter_matrices(deltap, task_list%pab_buffer, task_list, group)
     732             :          ELSE
     733       22721 :             CALL rs_copy_to_buffer(deltap, task_list%pab_buffer, task_list)
     734             :          END IF
     735       22757 :          DEALLOCATE (deltap)
     736             :       END IF
     737             : 
     738             :       ! Map all tasks from the grids
     739             :       CALL grid_integrate_task_list(task_list=task_list%grid_task_list, &
     740             :                                     compute_tau=my_compute_tau, &
     741             :                                     calculate_forces=calculate_forces, &
     742             :                                     calculate_virial=calculate_virial, &
     743             :                                     pab_blocks=task_list%pab_buffer, &
     744             :                                     rs_grids=rs_v, &
     745             :                                     hab_blocks=task_list%hab_buffer, &
     746             :                                     forces=forces_array, &
     747      180813 :                                     virial=virial_matrix)
     748             : 
     749      180813 :       IF (calculate_forces) THEN
     750       22757 :          CALL get_atomic_kind_set(atomic_kind_set, atom_of_kind=atom_of_kind, kind_of=kind_of)
     751             : !$OMP PARALLEL DO DEFAULT(NONE)  PRIVATE(atom_a, ikind) &
     752       22757 : !$OMP             SHARED(natoms, force, forces_array, atom_of_kind, kind_of, admm_scal_fac)
     753             :          DO iatom = 1, natoms
     754             :             atom_a = atom_of_kind(iatom)
     755             :             ikind = kind_of(iatom)
     756             :             force(ikind)%rho_elec(:, atom_a) = force(ikind)%rho_elec(:, atom_a) + admm_scal_fac*forces_array(:, iatom)
     757             :          END DO
     758             : !$OMP END PARALLEL DO
     759       22757 :          DEALLOCATE (atom_of_kind, kind_of)
     760             :       END IF
     761             : 
     762      180813 :       IF (calculate_virial) THEN
     763       46605 :          virial%pv_virial = virial%pv_virial + admm_scal_fac*virial_matrix
     764             :       END IF
     765             : 
     766             :       ! Gather all matrix images into a single array.
     767      833710 :       ALLOCATE (dhmat(nimages))
     768      180813 :       IF (PRESENT(hmat_kp)) THEN
     769      120565 :          CPASSERT(.NOT. PRESENT(hmat))
     770      351588 :          DO img = 1, nimages
     771      351588 :             dhmat(img)%matrix => hmat_kp(img)%matrix
     772             :          END DO
     773             :       ELSE
     774       60248 :          CPASSERT(PRESENT(hmat) .AND. nimages == 1)
     775       60248 :          dhmat(1)%matrix => hmat%matrix
     776             :       END IF
     777             : 
     778             :       ! Distribute matrix blocks.
     779      180813 :       IF (distributed_grids) THEN
     780         218 :          CALL rs_gather_matrices(task_list%hab_buffer, dhmat, task_list, group)
     781             :       ELSE
     782      180595 :          CALL rs_copy_to_matrices(task_list%hab_buffer, dhmat, task_list)
     783             :       END IF
     784      180813 :       DEALLOCATE (dhmat)
     785             : 
     786      180813 :       CALL timestop(handle)
     787             : 
     788      542439 :    END SUBROUTINE integrate_v_rspace
     789             : 
     790             : END MODULE qs_integrate_potential_product

Generated by: LCOV version 1.15