LCOV - code coverage report
Current view: top level - src - almo_scf_qs.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:2fce0f8) Lines: 432 532 81.2 %
Date: 2024-12-21 06:28:57 Functions: 11 11 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 Interface between ALMO SCF and QS
      10             : !> \par History
      11             : !>       2011.05 created [Rustam Z Khaliullin]
      12             : !> \author Rustam Z Khaliullin
      13             : ! **************************************************************************************************
      14             : MODULE almo_scf_qs
      15             :    USE almo_scf_types,                  ONLY: almo_mat_dim_aobasis,&
      16             :                                               almo_mat_dim_occ,&
      17             :                                               almo_mat_dim_virt,&
      18             :                                               almo_mat_dim_virt_disc,&
      19             :                                               almo_mat_dim_virt_full,&
      20             :                                               almo_scf_env_type
      21             :    USE atomic_kind_types,               ONLY: get_atomic_kind
      22             :    USE cell_types,                      ONLY: cell_type,&
      23             :                                               pbc
      24             :    USE cp_control_types,                ONLY: dft_control_type
      25             :    USE cp_dbcsr_api,                    ONLY: &
      26             :         dbcsr_complete_redistribute, dbcsr_copy, dbcsr_create, dbcsr_desymmetrize, &
      27             :         dbcsr_distribution_get, dbcsr_distribution_new, dbcsr_distribution_release, &
      28             :         dbcsr_distribution_type, dbcsr_filter, dbcsr_finalize, dbcsr_get_block_p, dbcsr_get_info, &
      29             :         dbcsr_get_num_blocks, dbcsr_get_stored_coordinates, dbcsr_multiply, dbcsr_nblkcols_total, &
      30             :         dbcsr_nblkrows_total, dbcsr_p_type, dbcsr_release, dbcsr_reserve_block2d, dbcsr_set, &
      31             :         dbcsr_type, dbcsr_type_no_symmetry, dbcsr_work_create
      32             :    USE cp_dbcsr_cp2k_link,              ONLY: cp_dbcsr_alloc_block_from_nbl
      33             :    USE cp_dbcsr_operations,             ONLY: dbcsr_allocate_matrix_set
      34             :    USE cp_fm_struct,                    ONLY: cp_fm_struct_create,&
      35             :                                               cp_fm_struct_release,&
      36             :                                               cp_fm_struct_type
      37             :    USE cp_fm_types,                     ONLY: cp_fm_create,&
      38             :                                               cp_fm_release,&
      39             :                                               cp_fm_type
      40             :    USE cp_log_handling,                 ONLY: cp_get_default_logger,&
      41             :                                               cp_logger_get_default_unit_nr,&
      42             :                                               cp_logger_type
      43             :    USE cp_units,                        ONLY: cp_unit_to_cp2k
      44             :    USE input_constants,                 ONLY: almo_constraint_ao_overlap,&
      45             :                                               almo_constraint_block_diagonal,&
      46             :                                               almo_constraint_distance,&
      47             :                                               almo_domain_layout_molecular,&
      48             :                                               almo_mat_distr_atomic,&
      49             :                                               almo_mat_distr_molecular,&
      50             :                                               do_bondparm_covalent,&
      51             :                                               do_bondparm_vdw
      52             :    USE kinds,                           ONLY: dp
      53             :    USE message_passing,                 ONLY: mp_comm_type
      54             :    USE molecule_types,                  ONLY: get_molecule_set_info,&
      55             :                                               molecule_type
      56             :    USE particle_types,                  ONLY: particle_type
      57             :    USE qs_energy_types,                 ONLY: qs_energy_type
      58             :    USE qs_environment_types,            ONLY: get_qs_env,&
      59             :                                               qs_environment_type,&
      60             :                                               set_qs_env
      61             :    USE qs_ks_methods,                   ONLY: qs_ks_update_qs_env
      62             :    USE qs_ks_types,                     ONLY: qs_ks_did_change,&
      63             :                                               qs_ks_env_type,&
      64             :                                               set_ks_env
      65             :    USE qs_mo_types,                     ONLY: allocate_mo_set,&
      66             :                                               deallocate_mo_set,&
      67             :                                               init_mo_set,&
      68             :                                               mo_set_type
      69             :    USE qs_neighbor_list_types,          ONLY: get_iterator_info,&
      70             :                                               neighbor_list_iterate,&
      71             :                                               neighbor_list_iterator_create,&
      72             :                                               neighbor_list_iterator_p_type,&
      73             :                                               neighbor_list_iterator_release,&
      74             :                                               neighbor_list_set_p_type
      75             :    USE qs_rho_methods,                  ONLY: qs_rho_update_rho
      76             :    USE qs_rho_types,                    ONLY: qs_rho_get,&
      77             :                                               qs_rho_type
      78             :    USE qs_scf_types,                    ONLY: qs_scf_env_type,&
      79             :                                               scf_env_create
      80             : #include "./base/base_uses.f90"
      81             : 
      82             :    IMPLICIT NONE
      83             : 
      84             :    PRIVATE
      85             : 
      86             :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'almo_scf_qs'
      87             : 
      88             :    PUBLIC :: matrix_almo_create, &
      89             :              almo_scf_construct_quencher, &
      90             :              calculate_w_matrix_almo, &
      91             :              init_almo_ks_matrix_via_qs, &
      92             :              almo_scf_update_ks_energy, &
      93             :              construct_qs_mos, &
      94             :              matrix_qs_to_almo, &
      95             :              almo_dm_to_almo_ks, &
      96             :              almo_dm_to_qs_env
      97             : 
      98             : CONTAINS
      99             : 
     100             : ! **************************************************************************************************
     101             : !> \brief create the ALMO matrix templates
     102             : !> \param matrix_new ...
     103             : !> \param matrix_qs ...
     104             : !> \param almo_scf_env ...
     105             : !> \param name_new ...
     106             : !> \param size_keys ...
     107             : !> \param symmetry_new ...
     108             : !> \param spin_key ...
     109             : !> \param init_domains ...
     110             : !> \par History
     111             : !>       2011.05 created [Rustam Z Khaliullin]
     112             : !> \author Rustam Z Khaliullin
     113             : ! **************************************************************************************************
     114        6568 :    SUBROUTINE matrix_almo_create(matrix_new, matrix_qs, almo_scf_env, &
     115             :                                  name_new, size_keys, symmetry_new, &
     116             :                                  spin_key, init_domains)
     117             : 
     118             :       TYPE(dbcsr_type)                                   :: matrix_new, matrix_qs
     119             :       TYPE(almo_scf_env_type), INTENT(IN)                :: almo_scf_env
     120             :       CHARACTER(len=*), INTENT(IN)                       :: name_new
     121             :       INTEGER, DIMENSION(2), INTENT(IN)                  :: size_keys
     122             :       CHARACTER, INTENT(IN)                              :: symmetry_new
     123             :       INTEGER, INTENT(IN)                                :: spin_key
     124             :       LOGICAL, INTENT(IN)                                :: init_domains
     125             : 
     126             :       CHARACTER(len=*), PARAMETER :: routineN = 'matrix_almo_create'
     127             : 
     128             :       INTEGER                                            :: dimen, handle, hold, iatom, iblock_col, &
     129             :                                                             iblock_row, imol, mynode, natoms, &
     130             :                                                             nblkrows_tot, nlength, nmols, row
     131        3284 :       INTEGER, DIMENSION(:), POINTER :: blk_distr, blk_sizes, block_sizes_new, col_distr_new, &
     132        3284 :          col_sizes_new, distr_new_array, row_distr_new, row_sizes_new
     133             :       LOGICAL                                            :: active, one_dim_is_mo, tr
     134        3284 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: p_new_block
     135             :       TYPE(dbcsr_distribution_type)                      :: dist_new, dist_qs
     136             : 
     137             : ! dimension size: AO, MO, etc
     138             : !                 almo_mat_dim_aobasis - no. of AOs,
     139             : !                 almo_mat_dim_occ     - no. of occupied MOs
     140             : !                 almo_mat_dim_domains - no. of domains
     141             : ! symmetry type: dbcsr_type_no_symmetry, dbcsr_type_symmetric,
     142             : !  dbcsr_type_antisymmetric, dbcsr_type_hermitian, dbcsr_type_antihermitian
     143             : !  (see dbcsr_lib/dbcsr_types.F for other values)
     144             : ! spin_key: either 1 or 2 (0 is allowed for matrics in the AO basis)
     145             : !    TYPE(dbcsr_iterator_type)                  :: iter
     146             : !    REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: allones
     147             : !-----------------------------------------------------------------------
     148             : 
     149        3284 :       CALL timeset(routineN, handle)
     150             : 
     151             :       ! RZK-warning The structure of the matrices can be optimized:
     152             :       ! 1. Diagonal matrices must be distributed evenly over the processes.
     153             :       !    This can be achieved by distributing cpus: 012012-rows and 001122-cols
     154             :       !    block_diagonal_flag is introduced but not used
     155             :       ! 2. Multiplication of diagonally dominant matrices will be faster
     156             :       !    if the diagonal blocks are local to the same processes.
     157             :       ! 3. Systems of molecules of drastically different sizes might need
     158             :       !    better distribution.
     159             : 
     160             :       ! obtain distribution from the qs matrix - it might be useful
     161             :       ! to get the structure of the AO dimensions
     162        3284 :       CALL dbcsr_get_info(matrix_qs, distribution=dist_qs)
     163             : 
     164        3284 :       natoms = almo_scf_env%natoms
     165        3284 :       nmols = almo_scf_env%nmolecules
     166             : 
     167        9852 :       DO dimen = 1, 2 ! 1 - row, 2 - column dimension
     168             : 
     169             :          ! distribution pattern is the same for all matrix types (ao, occ, virt)
     170        6568 :          IF (dimen == 1) THEN !rows
     171        3284 :             CALL dbcsr_distribution_get(dist_qs, row_dist=blk_distr)
     172             :          ELSE !columns
     173        3284 :             CALL dbcsr_distribution_get(dist_qs, col_dist=blk_distr)
     174             :          END IF
     175             : 
     176        6568 :          IF (size_keys(dimen) == almo_mat_dim_aobasis) THEN ! this dimension is AO
     177             : 
     178             :             ! structure of an AO dimension can be copied from matrix_qs
     179        2508 :             CALL dbcsr_get_info(matrix_qs, row_blk_size=blk_sizes)
     180             : 
     181             :             ! atomic clustering of AOs
     182        2508 :             IF (almo_scf_env%mat_distr_aos == almo_mat_distr_atomic) THEN
     183           0 :                ALLOCATE (block_sizes_new(natoms), distr_new_array(natoms))
     184           0 :                block_sizes_new(:) = blk_sizes(:)
     185           0 :                distr_new_array(:) = blk_distr(:)
     186             :                ! molecular clustering of AOs
     187        2508 :             ELSE IF (almo_scf_env%mat_distr_aos == almo_mat_distr_molecular) THEN
     188       10032 :                ALLOCATE (block_sizes_new(nmols), distr_new_array(nmols))
     189       20130 :                block_sizes_new(:) = 0
     190       45936 :                DO iatom = 1, natoms
     191             :                   block_sizes_new(almo_scf_env%domain_index_of_atom(iatom)) = &
     192             :                      block_sizes_new(almo_scf_env%domain_index_of_atom(iatom)) + &
     193       45936 :                      blk_sizes(iatom)
     194             :                END DO
     195       20130 :                DO imol = 1, nmols
     196             :                   distr_new_array(imol) = &
     197       20130 :                      blk_distr(almo_scf_env%first_atom_of_domain(imol))
     198             :                END DO
     199             :             ELSE
     200           0 :                CPABORT("Illegal distribution")
     201             :             END IF
     202             : 
     203             :          ELSE ! this dimension is not AO
     204             : 
     205             :             IF (size_keys(dimen) == almo_mat_dim_occ .OR. &
     206             :                 size_keys(dimen) == almo_mat_dim_virt .OR. &
     207        4060 :                 size_keys(dimen) == almo_mat_dim_virt_disc .OR. &
     208             :                 size_keys(dimen) == almo_mat_dim_virt_full) THEN ! this dim is MO
     209             : 
     210             :                ! atomic clustering of MOs
     211        4060 :                IF (almo_scf_env%mat_distr_mos == almo_mat_distr_atomic) THEN
     212           0 :                   nlength = natoms
     213           0 :                   ALLOCATE (block_sizes_new(nlength))
     214           0 :                   block_sizes_new(:) = 0
     215             :                   IF (size_keys(dimen) == almo_mat_dim_occ) THEN
     216             :                      ! currently distributing atomic distr of mos is not allowed
     217             :                      ! RZK-warning define nocc_of_atom and nvirt_atom to implement it
     218             :                      !block_sizes_new(:)=almo_scf_env%nocc_of_atom(:,spin_key)
     219             :                   ELSE IF (size_keys(dimen) == almo_mat_dim_virt) THEN
     220             :                      !block_sizes_new(:)=almo_scf_env%nvirt_of_atom(:,spin_key)
     221             :                   END IF
     222             :                   ! molecular clustering of MOs
     223        4060 :                ELSE IF (almo_scf_env%mat_distr_mos == almo_mat_distr_molecular) THEN
     224        4060 :                   nlength = nmols
     225       12180 :                   ALLOCATE (block_sizes_new(nlength))
     226        4060 :                   IF (size_keys(dimen) == almo_mat_dim_occ) THEN
     227       18520 :                      block_sizes_new(:) = almo_scf_env%nocc_of_domain(:, spin_key)
     228             :                      ! Handle zero-electron fragments by adding one-orbital that
     229             :                      ! must remain zero at all times
     230       18520 :                      WHERE (block_sizes_new == 0) block_sizes_new = 1
     231        1740 :                   ELSE IF (size_keys(dimen) == almo_mat_dim_virt_disc) THEN
     232           0 :                      block_sizes_new(:) = almo_scf_env%nvirt_disc_of_domain(:, spin_key)
     233        1740 :                   ELSE IF (size_keys(dimen) == almo_mat_dim_virt_full) THEN
     234        5556 :                      block_sizes_new(:) = almo_scf_env%nvirt_full_of_domain(:, spin_key)
     235        1044 :                   ELSE IF (size_keys(dimen) == almo_mat_dim_virt) THEN
     236        8334 :                      block_sizes_new(:) = almo_scf_env%nvirt_of_domain(:, spin_key)
     237             :                   END IF
     238             :                ELSE
     239           0 :                   CPABORT("Illegal distribution")
     240             :                END IF
     241             : 
     242             :             ELSE
     243             : 
     244           0 :                CPABORT("Illegal dimension")
     245             : 
     246             :             END IF ! end choosing dim size (occ, virt)
     247             : 
     248             :             ! distribution for MOs is copied from AOs
     249       12180 :             ALLOCATE (distr_new_array(nlength))
     250             :             ! atomic clustering
     251        4060 :             IF (almo_scf_env%mat_distr_mos == almo_mat_distr_atomic) THEN
     252           0 :                distr_new_array(:) = blk_distr(:)
     253             :                ! molecular clustering
     254        4060 :             ELSE IF (almo_scf_env%mat_distr_mos == almo_mat_distr_molecular) THEN
     255       32410 :                DO imol = 1, nmols
     256             :                   distr_new_array(imol) = &
     257       32410 :                      blk_distr(almo_scf_env%first_atom_of_domain(imol))
     258             :                END DO
     259             :             END IF
     260             :          END IF ! end choosing dimension size (AOs vs .NOT.AOs)
     261             : 
     262             :          ! create final arrays
     263        9852 :          IF (dimen == 1) THEN !rows
     264        3284 :             row_sizes_new => block_sizes_new
     265        3284 :             row_distr_new => distr_new_array
     266             :          ELSE !columns
     267        3284 :             col_sizes_new => block_sizes_new
     268        3284 :             col_distr_new => distr_new_array
     269             :          END IF
     270             :       END DO ! both rows and columns are done
     271             : 
     272             :       ! Create the distribution
     273             :       CALL dbcsr_distribution_new(dist_new, template=dist_qs, &
     274             :                                   row_dist=row_distr_new, col_dist=col_distr_new, &
     275        3284 :                                   reuse_arrays=.TRUE.)
     276             : 
     277             :       ! Create the matrix
     278             :       CALL dbcsr_create(matrix_new, name_new, &
     279             :                         dist_new, symmetry_new, &
     280        3284 :                         row_sizes_new, col_sizes_new, reuse_arrays=.TRUE.)
     281        3284 :       CALL dbcsr_distribution_release(dist_new)
     282             : 
     283             :       ! fill out reqired blocks with 1.0_dp to tell the dbcsr library
     284             :       ! which blocks to keep
     285        3284 :       IF (init_domains) THEN
     286             : 
     287        1312 :          CALL dbcsr_distribution_get(dist_new, mynode=mynode)
     288        1312 :          CALL dbcsr_work_create(matrix_new, work_mutable=.TRUE.)
     289             : 
     290             :          ! startQQQ - this part of the code scales quadratically
     291             :          ! therefore it is replaced with a less general but linear scaling algorithm below
     292             :          ! the quadratic algorithm is kept to be re-written later
     293             :          !QQQnblkrows_tot = dbcsr_nblkrows_total(matrix_new)
     294             :          !QQQnblkcols_tot = dbcsr_nblkcols_total(matrix_new)
     295             :          !QQQDO row = 1, nblkrows_tot
     296             :          !QQQ   DO col = 1, nblkcols_tot
     297             :          !QQQ      tr = .FALSE.
     298             :          !QQQ      iblock_row = row
     299             :          !QQQ      iblock_col = col
     300             :          !QQQ      CALL dbcsr_get_stored_coordinates(matrix_new, iblock_row, iblock_col, tr, hold)
     301             : 
     302             :          !QQQ      IF(hold.EQ.mynode) THEN
     303             :          !QQQ
     304             :          !QQQ         ! RZK-warning replace with a function which says if this
     305             :          !QQQ         ! distribution block is active or not
     306             :          !QQQ         ! Translate indeces of distribution blocks to domain blocks
     307             :          !QQQ         if (size_keys(1)==almo_mat_dim_aobasis) then
     308             :          !QQQ           domain_row=almo_scf_env%domain_index_of_ao_block(iblock_row)
     309             :          !QQQ         else if (size_keys(2)==almo_mat_dim_occ .OR. &
     310             :          !QQQ                  size_keys(2)==almo_mat_dim_virt .OR. &
     311             :          !QQQ                  size_keys(2)==almo_mat_dim_virt_disc .OR. &
     312             :          !QQQ                  size_keys(2)==almo_mat_dim_virt_full) then
     313             :          !QQQ           domain_row=almo_scf_env%domain_index_of_mo_block(iblock_row)
     314             :          !QQQ         else
     315             :          !QQQ           CPErrorMessage(cp_failure_level,routineP,"Illegal dimension")
     316             :          !QQQ           CPPrecondition(.FALSE.,cp_failure_level,routineP,failure)
     317             :          !QQQ         endif
     318             : 
     319             :          !QQQ         if (size_keys(2)==almo_mat_dim_aobasis) then
     320             :          !QQQ           domain_col=almo_scf_env%domain_index_of_ao_block(iblock_col)
     321             :          !QQQ         else if (size_keys(2)==almo_mat_dim_occ .OR. &
     322             :          !QQQ                  size_keys(2)==almo_mat_dim_virt .OR. &
     323             :          !QQQ                  size_keys(2)==almo_mat_dim_virt_disc .OR. &
     324             :          !QQQ                  size_keys(2)==almo_mat_dim_virt_full) then
     325             :          !QQQ           domain_col=almo_scf_env%domain_index_of_mo_block(iblock_col)
     326             :          !QQQ         else
     327             :          !QQQ           CPErrorMessage(cp_failure_level,routineP,"Illegal dimension")
     328             :          !QQQ           CPPrecondition(.FALSE.,cp_failure_level,routineP,failure)
     329             :          !QQQ         endif
     330             : 
     331             :          !QQQ         ! Finds if we need this block
     332             :          !QQQ         ! only the block-diagonal constraint is implemented here
     333             :          !QQQ         active=.false.
     334             :          !QQQ         if (domain_row==domain_col) active=.true.
     335             : 
     336             :          !QQQ         IF (active) THEN
     337             :          !QQQ            NULLIFY (p_new_block)
     338             :          !QQQ            CALL dbcsr_reserve_block2d(matrix_new, iblock_row, iblock_col, p_new_block)
     339             :          !QQQ            CPPostcondition(ASSOCIATED(p_new_block),cp_failure_level,routineP,failure)
     340             :          !QQQ            p_new_block(:,:) = 1.0_dp
     341             :          !QQQ         ENDIF
     342             : 
     343             :          !QQQ      ENDIF ! mynode
     344             :          !QQQ   ENDDO
     345             :          !QQQENDDO
     346             :          !QQQtake care of zero-electron fragments
     347             :          ! endQQQ - end of the quadratic part
     348             :          ! start linear-scaling replacement:
     349             :          ! works only for molecular blocks AND molecular distributions
     350        1312 :          nblkrows_tot = dbcsr_nblkrows_total(matrix_new)
     351       10528 :          DO row = 1, nblkrows_tot
     352        9216 :             tr = .FALSE.
     353        9216 :             iblock_row = row
     354        9216 :             iblock_col = row
     355        9216 :             CALL dbcsr_get_stored_coordinates(matrix_new, iblock_row, iblock_col, hold)
     356             : 
     357       10528 :             IF (hold .EQ. mynode) THEN
     358             : 
     359       13824 :                active = .TRUE.
     360             : 
     361             :                one_dim_is_mo = .FALSE.
     362       13824 :                DO dimen = 1, 2 ! 1 - row, 2 - column dimension
     363       13824 :                   IF (size_keys(dimen) == almo_mat_dim_occ) one_dim_is_mo = .TRUE.
     364             :                END DO
     365        4608 :                IF (one_dim_is_mo) THEN
     366        1620 :                   IF (almo_scf_env%nocc_of_domain(row, spin_key) == 0) active = .FALSE.
     367             :                END IF
     368             : 
     369        4608 :                one_dim_is_mo = .FALSE.
     370       13824 :                DO dimen = 1, 2
     371       13824 :                   IF (size_keys(dimen) == almo_mat_dim_virt) one_dim_is_mo = .TRUE.
     372             :                END DO
     373        4608 :                IF (one_dim_is_mo) THEN
     374         405 :                   IF (almo_scf_env%nvirt_of_domain(row, spin_key) == 0) active = .FALSE.
     375             :                END IF
     376             : 
     377        4608 :                one_dim_is_mo = .FALSE.
     378       13824 :                DO dimen = 1, 2
     379       13824 :                   IF (size_keys(dimen) == almo_mat_dim_virt_disc) one_dim_is_mo = .TRUE.
     380             :                END DO
     381        4608 :                IF (one_dim_is_mo) THEN
     382           0 :                   IF (almo_scf_env%nvirt_disc_of_domain(row, spin_key) == 0) active = .FALSE.
     383             :                END IF
     384             : 
     385        4608 :                one_dim_is_mo = .FALSE.
     386       13824 :                DO dimen = 1, 2
     387       13824 :                   IF (size_keys(dimen) == almo_mat_dim_virt_full) one_dim_is_mo = .TRUE.
     388             :                END DO
     389        4608 :                IF (one_dim_is_mo) THEN
     390         405 :                   IF (almo_scf_env%nvirt_full_of_domain(row, spin_key) == 0) active = .FALSE.
     391             :                END IF
     392             : 
     393        4574 :                IF (active) THEN
     394        4284 :                   NULLIFY (p_new_block)
     395        4284 :                   CALL dbcsr_reserve_block2d(matrix_new, iblock_row, iblock_col, p_new_block)
     396        4284 :                   CPASSERT(ASSOCIATED(p_new_block))
     397      837014 :                   p_new_block(:, :) = 1.0_dp
     398             :                END IF
     399             : 
     400             :             END IF ! mynode
     401             :          END DO
     402             :          ! end lnear-scaling replacement
     403             : 
     404             :       END IF ! init_domains
     405             : 
     406        3284 :       CALL dbcsr_finalize(matrix_new)
     407             : 
     408        3284 :       CALL timestop(handle)
     409             : 
     410        3284 :    END SUBROUTINE matrix_almo_create
     411             : 
     412             : ! **************************************************************************************************
     413             : !> \brief convert between two types of matrices: QS style to ALMO style
     414             : !> \param matrix_qs ...
     415             : !> \param matrix_almo ...
     416             : !> \param mat_distr_aos ...
     417             : !> \par History
     418             : !>       2011.06 created [Rustam Z Khaliullin]
     419             : !> \author Rustam Z Khaliullin
     420             : ! **************************************************************************************************
     421        2026 :    SUBROUTINE matrix_qs_to_almo(matrix_qs, matrix_almo, mat_distr_aos)
     422             : 
     423             :       TYPE(dbcsr_type)                                   :: matrix_qs, matrix_almo
     424             :       INTEGER                                            :: mat_distr_aos
     425             : 
     426             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'matrix_qs_to_almo'
     427             : 
     428             :       INTEGER                                            :: handle
     429             :       TYPE(dbcsr_type)                                   :: matrix_qs_nosym
     430             : 
     431        2026 :       CALL timeset(routineN, handle)
     432             :       !RZK-warning if it's not a N(AO)xN(AO) matrix then stop
     433             : 
     434        2026 :       SELECT CASE (mat_distr_aos)
     435             :       CASE (almo_mat_distr_atomic)
     436             :          ! automatic data_type conversion
     437           0 :          CALL dbcsr_copy(matrix_almo, matrix_qs)
     438             :       CASE (almo_mat_distr_molecular)
     439             :          ! desymmetrize the qs matrix
     440        2026 :          CALL dbcsr_create(matrix_qs_nosym, template=matrix_qs, matrix_type=dbcsr_type_no_symmetry)
     441        2026 :          CALL dbcsr_desymmetrize(matrix_qs, matrix_qs_nosym)
     442             : 
     443             :          ! perform the magic complete_redistribute
     444             :          ! before calling complete_redistribute set all blocks to zero
     445             :          ! otherwise the non-zero elements of the redistributed matrix,
     446             :          ! which are in zero-blocks of the original matrix, will remain
     447             :          ! in the final redistributed matrix. this is a bug in
     448             :          ! complete_redistribute. RZK-warning it should be later corrected by calling
     449             :          ! dbcsr_set to 0.0 from within complete_redistribute
     450        2026 :          CALL dbcsr_set(matrix_almo, 0.0_dp)
     451        2026 :          CALL dbcsr_complete_redistribute(matrix_qs_nosym, matrix_almo)
     452        2026 :          CALL dbcsr_release(matrix_qs_nosym)
     453             : 
     454             :       CASE DEFAULT
     455        2026 :          CPABORT("")
     456             :       END SELECT
     457             : 
     458        2026 :       CALL timestop(handle)
     459             : 
     460        2026 :    END SUBROUTINE matrix_qs_to_almo
     461             : 
     462             : ! **************************************************************************************************
     463             : !> \brief convert between two types of matrices: ALMO style to QS style
     464             : !> \param matrix_almo ...
     465             : !> \param matrix_qs ...
     466             : !> \param mat_distr_aos ...
     467             : !> \par History
     468             : !>       2011.06 created [Rustam Z Khaliullin]
     469             : !> \author Rustam Z Khaliullin
     470             : ! **************************************************************************************************
     471        1826 :    SUBROUTINE matrix_almo_to_qs(matrix_almo, matrix_qs, mat_distr_aos)
     472             :       TYPE(dbcsr_type)                                   :: matrix_almo, matrix_qs
     473             :       INTEGER, INTENT(IN)                                :: mat_distr_aos
     474             : 
     475             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'matrix_almo_to_qs'
     476             : 
     477             :       INTEGER                                            :: handle
     478             :       TYPE(dbcsr_type)                                   :: matrix_almo_redist
     479             : 
     480        1826 :       CALL timeset(routineN, handle)
     481             :       ! RZK-warning if it's not a N(AO)xN(AO) matrix then stop
     482             : 
     483        1826 :       SELECT CASE (mat_distr_aos)
     484             :       CASE (almo_mat_distr_atomic)
     485           0 :          CALL dbcsr_copy(matrix_qs, matrix_almo, keep_sparsity=.TRUE.)
     486             :       CASE (almo_mat_distr_molecular)
     487        1826 :          CALL dbcsr_create(matrix_almo_redist, template=matrix_qs)
     488        1826 :          CALL dbcsr_complete_redistribute(matrix_almo, matrix_almo_redist)
     489        1826 :          CALL dbcsr_set(matrix_qs, 0.0_dp)
     490        1826 :          CALL dbcsr_copy(matrix_qs, matrix_almo_redist, keep_sparsity=.TRUE.)
     491        1826 :          CALL dbcsr_release(matrix_almo_redist)
     492             :       CASE DEFAULT
     493        1826 :          CPABORT("")
     494             :       END SELECT
     495             : 
     496        1826 :       CALL timestop(handle)
     497             : 
     498        1826 :    END SUBROUTINE matrix_almo_to_qs
     499             : 
     500             : ! **************************************************************************************************
     501             : !> \brief Initialization of the QS and ALMO KS matrix
     502             : !> \param qs_env ...
     503             : !> \param matrix_ks ...
     504             : !> \param mat_distr_aos ...
     505             : !> \param eps_filter ...
     506             : !> \par History
     507             : !>       2011.05 created [Rustam Z Khaliullin]
     508             : !> \author Rustam Z Khaliullin
     509             : ! **************************************************************************************************
     510         116 :    SUBROUTINE init_almo_ks_matrix_via_qs(qs_env, matrix_ks, mat_distr_aos, eps_filter)
     511             : 
     512             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     513             :       TYPE(dbcsr_type), DIMENSION(:)                     :: matrix_ks
     514             :       INTEGER                                            :: mat_distr_aos
     515             :       REAL(KIND=dp)                                      :: eps_filter
     516             : 
     517             :       CHARACTER(len=*), PARAMETER :: routineN = 'init_almo_ks_matrix_via_qs'
     518             : 
     519             :       INTEGER                                            :: handle, ispin, nspin
     520         116 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_qs_ks, matrix_qs_s
     521             :       TYPE(dft_control_type), POINTER                    :: dft_control
     522             :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
     523         116 :          POINTER                                         :: sab_orb
     524             :       TYPE(qs_ks_env_type), POINTER                      :: ks_env
     525             : 
     526         116 :       CALL timeset(routineN, handle)
     527             : 
     528         116 :       NULLIFY (sab_orb)
     529             : 
     530             :       ! get basic quantities from the qs_env
     531             :       CALL get_qs_env(qs_env, &
     532             :                       dft_control=dft_control, &
     533             :                       matrix_s=matrix_qs_s, &
     534             :                       matrix_ks=matrix_qs_ks, &
     535             :                       ks_env=ks_env, &
     536         116 :                       sab_orb=sab_orb)
     537             : 
     538         116 :       nspin = dft_control%nspins
     539             : 
     540             :       ! create matrix_ks in the QS env if necessary
     541         116 :       IF (.NOT. ASSOCIATED(matrix_qs_ks)) THEN
     542           0 :          CALL dbcsr_allocate_matrix_set(matrix_qs_ks, nspin)
     543           0 :          DO ispin = 1, nspin
     544           0 :             ALLOCATE (matrix_qs_ks(ispin)%matrix)
     545             :             CALL dbcsr_create(matrix_qs_ks(ispin)%matrix, &
     546           0 :                               template=matrix_qs_s(1)%matrix)
     547           0 :             CALL cp_dbcsr_alloc_block_from_nbl(matrix_qs_ks(ispin)%matrix, sab_orb)
     548           0 :             CALL dbcsr_set(matrix_qs_ks(ispin)%matrix, 0.0_dp)
     549             :          END DO
     550           0 :          CALL set_ks_env(ks_env, matrix_ks=matrix_qs_ks)
     551             :       END IF
     552             : 
     553             :       ! copy to ALMO
     554         232 :       DO ispin = 1, nspin
     555         116 :          CALL matrix_qs_to_almo(matrix_qs_ks(ispin)%matrix, matrix_ks(ispin), mat_distr_aos)
     556         232 :          CALL dbcsr_filter(matrix_ks(ispin), eps_filter)
     557             :       END DO
     558             : 
     559         116 :       CALL timestop(handle)
     560             : 
     561         116 :    END SUBROUTINE init_almo_ks_matrix_via_qs
     562             : 
     563             : ! **************************************************************************************************
     564             : !> \brief Create MOs in the QS env to be able to return ALMOs to QS
     565             : !> \param qs_env ...
     566             : !> \param almo_scf_env ...
     567             : !> \par History
     568             : !>       2016.12 created [Yifei Shi]
     569             : !> \author Yifei Shi
     570             : ! **************************************************************************************************
     571         348 :    SUBROUTINE construct_qs_mos(qs_env, almo_scf_env)
     572             : 
     573             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     574             :       TYPE(almo_scf_env_type), INTENT(INOUT)             :: almo_scf_env
     575             : 
     576             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'construct_qs_mos'
     577             : 
     578             :       INTEGER                                            :: handle, ispin, ncol_fm, nrow_fm
     579             :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct_tmp
     580             :       TYPE(cp_fm_type)                                   :: mo_fm_copy
     581             :       TYPE(dft_control_type), POINTER                    :: dft_control
     582         116 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
     583             :       TYPE(qs_scf_env_type), POINTER                     :: scf_env
     584             : 
     585         116 :       CALL timeset(routineN, handle)
     586             : 
     587             :       ! create and init scf_env (this is necessary to return MOs to qs)
     588         116 :       NULLIFY (mos, fm_struct_tmp, scf_env)
     589         116 :       ALLOCATE (scf_env)
     590         116 :       CALL scf_env_create(scf_env)
     591             : 
     592             :       !CALL qs_scf_env_initialize(qs_env, scf_env)
     593         116 :       CALL set_qs_env(qs_env, scf_env=scf_env)
     594         116 :       CALL get_qs_env(qs_env, dft_control=dft_control, mos=mos)
     595             : 
     596         116 :       CALL dbcsr_get_info(almo_scf_env%matrix_t(1), nfullrows_total=nrow_fm, nfullcols_total=ncol_fm)
     597             : 
     598             :       ! allocate and init mo_set
     599         232 :       DO ispin = 1, almo_scf_env%nspins
     600             : 
     601             :          ! Currently only fm version of mo_set is usable.
     602             :          ! First transform the matrix_t to fm version
     603             :          ! Empty the containers to prevent memory leaks
     604         116 :          CALL deallocate_mo_set(mos(ispin))
     605             :          CALL allocate_mo_set(mo_set=mos(ispin), &
     606             :                               nao=nrow_fm, &
     607             :                               nmo=ncol_fm, &
     608             :                               nelectron=almo_scf_env%nelectrons_total, &
     609             :                               n_el_f=REAL(almo_scf_env%nelectrons_total, dp), &
     610             :                               maxocc=2.0_dp, &
     611         116 :                               flexible_electron_count=dft_control%relax_multiplicity)
     612             : 
     613             :          CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nrow_fm, ncol_global=ncol_fm, &
     614             :                                   context=almo_scf_env%blacs_env, &
     615         116 :                                   para_env=almo_scf_env%para_env)
     616             : 
     617         116 :          CALL cp_fm_create(mo_fm_copy, fm_struct_tmp, name="t_orthogonal_converted_to_fm")
     618         116 :          CALL cp_fm_struct_release(fm_struct_tmp)
     619             :          !CALL copy_dbcsr_to_fm(almo_scf_env%matrix_t(ispin), mo_fm_copy)
     620             : 
     621         116 :          CALL init_mo_set(mos(ispin), fm_ref=mo_fm_copy, name='fm_mo')
     622             : 
     623         348 :          CALL cp_fm_release(mo_fm_copy)
     624             : 
     625             :       END DO
     626             : 
     627         116 :       CALL timestop(handle)
     628             : 
     629         116 :    END SUBROUTINE construct_qs_mos
     630             : 
     631             : ! **************************************************************************************************
     632             : !> \brief return density matrix to the qs_env
     633             : !> \param qs_env ...
     634             : !> \param matrix_p ...
     635             : !> \param mat_distr_aos ...
     636             : !> \par History
     637             : !>       2011.05 created [Rustam Z Khaliullin]
     638             : !> \author Rustam Z Khaliullin
     639             : ! **************************************************************************************************
     640        1760 :    SUBROUTINE almo_dm_to_qs_env(qs_env, matrix_p, mat_distr_aos)
     641             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     642             :       TYPE(dbcsr_type), DIMENSION(:)                     :: matrix_p
     643             :       INTEGER, INTENT(IN)                                :: mat_distr_aos
     644             : 
     645             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'almo_dm_to_qs_env'
     646             : 
     647             :       INTEGER                                            :: handle, ispin, nspins
     648        1760 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: rho_ao
     649             :       TYPE(qs_rho_type), POINTER                         :: rho
     650             : 
     651        1760 :       CALL timeset(routineN, handle)
     652             : 
     653        1760 :       NULLIFY (rho, rho_ao)
     654        1760 :       nspins = SIZE(matrix_p)
     655        1760 :       CALL get_qs_env(qs_env, rho=rho)
     656        1760 :       CALL qs_rho_get(rho, rho_ao=rho_ao)
     657             : 
     658             :       ! set the new density matrix
     659        3520 :       DO ispin = 1, nspins
     660             :          CALL matrix_almo_to_qs(matrix_p(ispin), &
     661             :                                 rho_ao(ispin)%matrix, &
     662        3520 :                                 mat_distr_aos)
     663             :       END DO
     664        1760 :       CALL qs_rho_update_rho(rho, qs_env=qs_env)
     665        1760 :       CALL qs_ks_did_change(qs_env%ks_env, rho_changed=.TRUE.)
     666             : 
     667        1760 :       CALL timestop(handle)
     668             : 
     669        1760 :    END SUBROUTINE almo_dm_to_qs_env
     670             : 
     671             : ! **************************************************************************************************
     672             : !> \brief uses the ALMO density matrix
     673             : !>        to compute KS matrix (inside QS environment) and the new energy
     674             : !> \param qs_env ...
     675             : !> \param matrix_p ...
     676             : !> \param energy_total ...
     677             : !> \param mat_distr_aos ...
     678             : !> \param smear ...
     679             : !> \param kTS_sum ...
     680             : !> \par History
     681             : !>       2011.05 created [Rustam Z Khaliullin]
     682             : !>       2018.09 smearing support [Ruben Staub]
     683             : !> \author Rustam Z Khaliullin
     684             : ! **************************************************************************************************
     685        1734 :    SUBROUTINE almo_dm_to_qs_ks(qs_env, matrix_p, energy_total, mat_distr_aos, smear, kTS_sum)
     686             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     687             :       TYPE(dbcsr_type), DIMENSION(:)                     :: matrix_p
     688             :       REAL(KIND=dp)                                      :: energy_total
     689             :       INTEGER, INTENT(IN)                                :: mat_distr_aos
     690             :       LOGICAL, INTENT(IN), OPTIONAL                      :: smear
     691             :       REAL(KIND=dp), INTENT(IN), OPTIONAL                :: kTS_sum
     692             : 
     693             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'almo_dm_to_qs_ks'
     694             : 
     695             :       INTEGER                                            :: handle
     696             :       LOGICAL                                            :: smearing
     697             :       REAL(KIND=dp)                                      :: entropic_term
     698             :       TYPE(qs_energy_type), POINTER                      :: energy
     699             : 
     700        1734 :       CALL timeset(routineN, handle)
     701             : 
     702        1734 :       IF (PRESENT(smear)) THEN
     703        1734 :          smearing = smear
     704             :       ELSE
     705             :          smearing = .FALSE.
     706             :       END IF
     707             : 
     708        1734 :       IF (PRESENT(kTS_sum)) THEN
     709        1734 :          entropic_term = kTS_sum
     710             :       ELSE
     711             :          entropic_term = 0.0_dp
     712             :       END IF
     713             : 
     714        1734 :       NULLIFY (energy)
     715        1734 :       CALL get_qs_env(qs_env, energy=energy)
     716        1734 :       CALL almo_dm_to_qs_env(qs_env, matrix_p, mat_distr_aos)
     717             :       CALL qs_ks_update_qs_env(qs_env, calculate_forces=.FALSE., just_energy=.FALSE., &
     718        1734 :                                print_active=.TRUE.)
     719             : 
     720             :       !! Add electronic entropy contribution if smearing is requested
     721             :       !! Previous QS entropy is replaced by the sum of the entropy for each spin
     722        1734 :       IF (smearing) THEN
     723          20 :          energy%total = energy%total - energy%kTS + entropic_term
     724             :       END IF
     725             : 
     726        1734 :       energy_total = energy%total
     727             : 
     728        1734 :       CALL timestop(handle)
     729             : 
     730        1734 :    END SUBROUTINE almo_dm_to_qs_ks
     731             : 
     732             : ! **************************************************************************************************
     733             : !> \brief uses the ALMO density matrix
     734             : !>        to compute ALMO KS matrix and the new energy
     735             : !> \param qs_env ...
     736             : !> \param matrix_p ...
     737             : !> \param matrix_ks ...
     738             : !> \param energy_total ...
     739             : !> \param eps_filter ...
     740             : !> \param mat_distr_aos ...
     741             : !> \param smear ...
     742             : !> \param kTS_sum ...
     743             : !> \par History
     744             : !>       2011.05 created [Rustam Z Khaliullin]
     745             : !>       2018.09 smearing support [Ruben Staub]
     746             : !> \author Rustam Z Khaliullin
     747             : ! **************************************************************************************************
     748        1734 :    SUBROUTINE almo_dm_to_almo_ks(qs_env, matrix_p, matrix_ks, energy_total, eps_filter, &
     749             :                                  mat_distr_aos, smear, kTS_sum)
     750             : 
     751             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     752             :       TYPE(dbcsr_type), DIMENSION(:)                     :: matrix_p, matrix_ks
     753             :       REAL(KIND=dp)                                      :: energy_total, eps_filter
     754             :       INTEGER, INTENT(IN)                                :: mat_distr_aos
     755             :       LOGICAL, INTENT(IN), OPTIONAL                      :: smear
     756             :       REAL(KIND=dp), INTENT(IN), OPTIONAL                :: kTS_sum
     757             : 
     758             :       CHARACTER(len=*), PARAMETER :: routineN = 'almo_dm_to_almo_ks'
     759             : 
     760             :       INTEGER                                            :: handle, ispin, nspins
     761             :       LOGICAL                                            :: smearing
     762             :       REAL(KIND=dp)                                      :: entropic_term
     763        1734 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_qs_ks
     764             : 
     765        1734 :       CALL timeset(routineN, handle)
     766             : 
     767        1734 :       IF (PRESENT(smear)) THEN
     768         464 :          smearing = smear
     769             :       ELSE
     770        1270 :          smearing = .FALSE.
     771             :       END IF
     772             : 
     773        1734 :       IF (PRESENT(kTS_sum)) THEN
     774         464 :          entropic_term = kTS_sum
     775             :       ELSE
     776        1270 :          entropic_term = 0.0_dp
     777             :       END IF
     778             : 
     779             :       ! update KS matrix in the QS env
     780             :       CALL almo_dm_to_qs_ks(qs_env, matrix_p, energy_total, mat_distr_aos, &
     781             :                             smear=smearing, &
     782        1734 :                             kTS_sum=entropic_term)
     783             : 
     784        1734 :       nspins = SIZE(matrix_ks)
     785             : 
     786             :       ! get KS matrix from the QS env and convert to the ALMO format
     787        1734 :       CALL get_qs_env(qs_env, matrix_ks=matrix_qs_ks)
     788        3468 :       DO ispin = 1, nspins
     789        1734 :          CALL matrix_qs_to_almo(matrix_qs_ks(ispin)%matrix, matrix_ks(ispin), mat_distr_aos)
     790        3468 :          CALL dbcsr_filter(matrix_ks(ispin), eps_filter)
     791             :       END DO
     792             : 
     793        1734 :       CALL timestop(handle)
     794             : 
     795        1734 :    END SUBROUTINE almo_dm_to_almo_ks
     796             : 
     797             : ! **************************************************************************************************
     798             : !> \brief update qs_env total energy
     799             : !> \param qs_env ...
     800             : !> \param energy ...
     801             : !> \param energy_singles_corr ...
     802             : !> \par History
     803             : !>       2013.03 created [Rustam Z Khaliullin]
     804             : !> \author Rustam Z Khaliullin
     805             : ! **************************************************************************************************
     806         106 :    SUBROUTINE almo_scf_update_ks_energy(qs_env, energy, energy_singles_corr)
     807             : 
     808             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     809             :       REAL(KIND=dp), INTENT(IN), OPTIONAL                :: energy, energy_singles_corr
     810             : 
     811             :       TYPE(qs_energy_type), POINTER                      :: qs_energy
     812             : 
     813         106 :       CALL get_qs_env(qs_env, energy=qs_energy)
     814             : 
     815         106 :       IF (PRESENT(energy_singles_corr)) THEN
     816          26 :          qs_energy%singles_corr = energy_singles_corr
     817             :       ELSE
     818          80 :          qs_energy%singles_corr = 0.0_dp
     819             :       END IF
     820             : 
     821         106 :       IF (PRESENT(energy)) THEN
     822         106 :          qs_energy%total = energy
     823             :       END IF
     824             : 
     825         106 :       qs_energy%total = qs_energy%total + qs_energy%singles_corr
     826             : 
     827         106 :    END SUBROUTINE almo_scf_update_ks_energy
     828             : 
     829             : ! **************************************************************************************************
     830             : !> \brief Creates the matrix that imposes absolute locality on MOs
     831             : !> \param qs_env ...
     832             : !> \param almo_scf_env ...
     833             : !> \par History
     834             : !>       2011.11 created [Rustam Z. Khaliullin]
     835             : !> \author Rustam Z. Khaliullin
     836             : ! **************************************************************************************************
     837         116 :    SUBROUTINE almo_scf_construct_quencher(qs_env, almo_scf_env)
     838             : 
     839             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     840             :       TYPE(almo_scf_env_type), INTENT(INOUT)             :: almo_scf_env
     841             : 
     842             :       CHARACTER(len=*), PARAMETER :: routineN = 'almo_scf_construct_quencher'
     843             : 
     844             :       CHARACTER                                          :: sym
     845             :       INTEGER :: col, contact_atom_1, contact_atom_2, domain_col, domain_map_local_entries, &
     846             :          domain_row, global_entries, global_list_length, grid1, GroupID, handle, hold, iatom, &
     847             :          iatom2, iblock_col, iblock_row, idomain, idomain2, ientry, igrid, ineig, ineighbor, &
     848             :          iNode, inode2, ipair, ispin, jatom, jatom2, jdomain2, local_list_length, &
     849             :          max_domain_neighbors, max_neig, mynode, nblkcols_tot, nblkrows_tot, nblks, ndomains, &
     850             :          neig_temp, nnode2, nNodes, row, unit_nr
     851         116 :       INTEGER, ALLOCATABLE, DIMENSION(:) :: current_number_neighbors, domain_entries_cpu, &
     852         116 :          domain_map_global, domain_map_local, first_atom_of_molecule, global_list, &
     853         116 :          last_atom_of_molecule, list_length_cpu, list_offset_cpu, local_list, offset_for_cpu
     854         116 :       INTEGER, ALLOCATABLE, DIMENSION(:, :)              :: domain_grid, domain_neighbor_list, &
     855         116 :                                                             domain_neighbor_list_excessive
     856             :       LOGICAL                                            :: already_listed, block_active, &
     857             :                                                             delayed_increment, found, &
     858             :                                                             max_neig_fails, tr
     859             :       REAL(KIND=dp)                                      :: contact1_radius, contact2_radius, &
     860             :                                                             distance, distance_squared, overlap, &
     861             :                                                             r0, r1, s0, s1, trial_distance_squared
     862             :       REAL(KIND=dp), DIMENSION(3)                        :: rab
     863         116 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: p_new_block
     864             :       TYPE(cell_type), POINTER                           :: cell
     865             :       TYPE(cp_logger_type), POINTER                      :: logger
     866             :       TYPE(dbcsr_distribution_type)                      :: dist
     867         116 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_s
     868             :       TYPE(dbcsr_type)                                   :: matrix_s_sym
     869         116 :       TYPE(molecule_type), DIMENSION(:), POINTER         :: molecule_set
     870             :       TYPE(mp_comm_type)                                 :: group
     871             :       TYPE(neighbor_list_iterator_p_type), &
     872         116 :          DIMENSION(:), POINTER                           :: nl_iterator, nl_iterator2
     873             :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
     874         116 :          POINTER                                         :: sab_almo
     875         116 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     876             : 
     877         116 :       CALL timeset(routineN, handle)
     878             : 
     879             :       ! get a useful output_unit
     880         116 :       logger => cp_get_default_logger()
     881         116 :       IF (logger%para_env%is_source()) THEN
     882          58 :          unit_nr = cp_logger_get_default_unit_nr(logger, local=.TRUE.)
     883             :       ELSE
     884             :          unit_nr = -1
     885             :       END IF
     886             : 
     887         116 :       ndomains = almo_scf_env%ndomains
     888             : 
     889             :       CALL get_qs_env(qs_env=qs_env, &
     890             :                       particle_set=particle_set, &
     891             :                       molecule_set=molecule_set, &
     892             :                       cell=cell, &
     893             :                       matrix_s=matrix_s, &
     894         116 :                       sab_almo=sab_almo)
     895             : 
     896             :       ! if we are dealing with molecules get info about them
     897         116 :       IF (almo_scf_env%domain_layout_mos == almo_domain_layout_molecular .OR. &
     898             :           almo_scf_env%domain_layout_aos == almo_domain_layout_molecular) THEN
     899         348 :          ALLOCATE (first_atom_of_molecule(almo_scf_env%nmolecules))
     900         232 :          ALLOCATE (last_atom_of_molecule(almo_scf_env%nmolecules))
     901             :          CALL get_molecule_set_info(molecule_set, &
     902             :                                     mol_to_first_atom=first_atom_of_molecule, &
     903         116 :                                     mol_to_last_atom=last_atom_of_molecule)
     904             :       END IF
     905             : 
     906             :       ! create a symmetrized copy of the ao overlap
     907             :       CALL dbcsr_create(matrix_s_sym, &
     908             :                         template=almo_scf_env%matrix_s(1), &
     909         116 :                         matrix_type=dbcsr_type_no_symmetry)
     910             :       CALL dbcsr_get_info(almo_scf_env%matrix_s(1), &
     911         116 :                           matrix_type=sym)
     912         116 :       IF (sym .EQ. dbcsr_type_no_symmetry) THEN
     913           0 :          CALL dbcsr_copy(matrix_s_sym, almo_scf_env%matrix_s(1))
     914             :       ELSE
     915             :          CALL dbcsr_desymmetrize(almo_scf_env%matrix_s(1), &
     916         116 :                                  matrix_s_sym)
     917             :       END IF
     918             : 
     919         464 :       ALLOCATE (almo_scf_env%quench_t(almo_scf_env%nspins))
     920         464 :       ALLOCATE (almo_scf_env%domain_map(almo_scf_env%nspins))
     921             : 
     922             :       !DO ispin=1,almo_scf_env%nspins
     923         116 :       ispin = 1
     924             : 
     925             :       ! create the sparsity template for the occupied orbitals
     926             :       CALL matrix_almo_create(matrix_new=almo_scf_env%quench_t(ispin), &
     927             :                               matrix_qs=matrix_s(1)%matrix, &
     928             :                               almo_scf_env=almo_scf_env, &
     929             :                               name_new="T_QUENCHER", &
     930             :                               size_keys=(/almo_mat_dim_aobasis, almo_mat_dim_occ/), &
     931             :                               symmetry_new=dbcsr_type_no_symmetry, &
     932             :                               spin_key=ispin, &
     933         116 :                               init_domains=.FALSE.)
     934             : 
     935             :       ! initialize distance quencher
     936             :       CALL dbcsr_work_create(almo_scf_env%quench_t(ispin), &
     937         116 :                              work_mutable=.TRUE.)
     938             : 
     939         116 :       nblkrows_tot = dbcsr_nblkrows_total(almo_scf_env%quench_t(ispin))
     940             :       nblkcols_tot = dbcsr_nblkcols_total(almo_scf_env%quench_t(ispin))
     941             : 
     942         116 :       CALL dbcsr_get_info(almo_scf_env%quench_t(ispin), distribution=dist)
     943         116 :       CALL dbcsr_distribution_get(dist, numnodes=nNodes, group=GroupID, mynode=mynode)
     944         116 :       CALL group%set_handle(groupid)
     945             : 
     946             :       ! create global atom neighbor list from the local lists
     947             :       ! first, calculate number of local pairs
     948         116 :       local_list_length = 0
     949         116 :       CALL neighbor_list_iterator_create(nl_iterator, sab_almo)
     950       39355 :       DO WHILE (neighbor_list_iterate(nl_iterator) == 0)
     951             :          ! nnode - total number of neighbors for iatom
     952             :          ! inode - current neighbor count
     953             :          CALL get_iterator_info(nl_iterator, &
     954       39239 :                                 iatom=iatom2, jatom=jatom2, inode=inode2, nnode=nnode2)
     955             :          !WRITE(*,*) "GET INFO: ",iatom2, jatom2, inode2, nnode2
     956       39355 :          IF (inode2 == 1) THEN
     957        2001 :             local_list_length = local_list_length + nnode2
     958             :          END IF
     959             :       END DO
     960         116 :       CALL neighbor_list_iterator_release(nl_iterator)
     961             : 
     962             :       ! second, extract the local list to an array
     963         347 :       ALLOCATE (local_list(2*local_list_length))
     964       78594 :       local_list(:) = 0
     965         116 :       local_list_length = 0
     966         116 :       CALL neighbor_list_iterator_create(nl_iterator2, sab_almo)
     967       39355 :       DO WHILE (neighbor_list_iterate(nl_iterator2) == 0)
     968             :          CALL get_iterator_info(nl_iterator2, &
     969       39239 :                                 iatom=iatom2, jatom=jatom2)
     970       39239 :          local_list(2*local_list_length + 1) = iatom2
     971       39239 :          local_list(2*local_list_length + 2) = jatom2
     972       39239 :          local_list_length = local_list_length + 1
     973             :       END DO ! end loop over pairs of atoms
     974         116 :       CALL neighbor_list_iterator_release(nl_iterator2)
     975             : 
     976             :       ! third, communicate local length to the other nodes
     977         464 :       ALLOCATE (list_length_cpu(nNodes), list_offset_cpu(nNodes))
     978         116 :       CALL group%allgather(2*local_list_length, list_length_cpu)
     979             : 
     980             :       ! fourth, create a global list
     981         116 :       list_offset_cpu(1) = 0
     982         232 :       DO iNode = 2, nNodes
     983             :          list_offset_cpu(iNode) = list_offset_cpu(iNode - 1) + &
     984         232 :                                   list_length_cpu(iNode - 1)
     985             :       END DO
     986         116 :       global_list_length = list_offset_cpu(nNodes) + list_length_cpu(nNodes)
     987             : 
     988             :       ! fifth, communicate all list data
     989         348 :       ALLOCATE (global_list(global_list_length))
     990             :       CALL group%allgatherv(local_list, global_list, &
     991         116 :                             list_length_cpu, list_offset_cpu)
     992         116 :       DEALLOCATE (list_length_cpu, list_offset_cpu)
     993         116 :       DEALLOCATE (local_list)
     994             : 
     995             :       ! calculate maximum number of atoms surrounding the domain
     996         348 :       ALLOCATE (current_number_neighbors(almo_scf_env%ndomains))
     997         926 :       current_number_neighbors(:) = 0
     998         116 :       global_list_length = global_list_length/2
     999       78594 :       DO ipair = 1, global_list_length
    1000       78478 :          iatom2 = global_list(2*(ipair - 1) + 1)
    1001       78478 :          jatom2 = global_list(2*(ipair - 1) + 2)
    1002       78478 :          idomain2 = almo_scf_env%domain_index_of_atom(iatom2)
    1003       78478 :          jdomain2 = almo_scf_env%domain_index_of_atom(jatom2)
    1004             :          ! add to the list
    1005       78478 :          current_number_neighbors(idomain2) = current_number_neighbors(idomain2) + 1
    1006             :          ! add j,i with i,j
    1007       78594 :          IF (idomain2 .NE. jdomain2) THEN
    1008       62940 :             current_number_neighbors(jdomain2) = current_number_neighbors(jdomain2) + 1
    1009             :          END IF
    1010             :       END DO
    1011         926 :       max_domain_neighbors = MAXVAL(current_number_neighbors)
    1012             : 
    1013             :       ! use the global atom neighbor list to create a global domain neighbor list
    1014         464 :       ALLOCATE (domain_neighbor_list_excessive(ndomains, max_domain_neighbors))
    1015         926 :       current_number_neighbors(:) = 1
    1016         926 :       DO ipair = 1, ndomains
    1017         926 :          domain_neighbor_list_excessive(ipair, 1) = ipair
    1018             :       END DO
    1019       78594 :       DO ipair = 1, global_list_length
    1020       78478 :          iatom2 = global_list(2*(ipair - 1) + 1)
    1021       78478 :          jatom2 = global_list(2*(ipair - 1) + 2)
    1022       78478 :          idomain2 = almo_scf_env%domain_index_of_atom(iatom2)
    1023       78478 :          jdomain2 = almo_scf_env%domain_index_of_atom(jatom2)
    1024       78478 :          already_listed = .FALSE.
    1025      325246 :          DO ineighbor = 1, current_number_neighbors(idomain2)
    1026      325246 :             IF (domain_neighbor_list_excessive(idomain2, ineighbor) .EQ. jdomain2) THEN
    1027             :                already_listed = .TRUE.
    1028             :                EXIT
    1029             :             END IF
    1030             :          END DO
    1031       78594 :          IF (.NOT. already_listed) THEN
    1032             :             ! add to the list
    1033        2710 :             current_number_neighbors(idomain2) = current_number_neighbors(idomain2) + 1
    1034        2710 :             domain_neighbor_list_excessive(idomain2, current_number_neighbors(idomain2)) = jdomain2
    1035             :             ! add j,i with i,j
    1036        2710 :             IF (idomain2 .NE. jdomain2) THEN
    1037        2710 :                current_number_neighbors(jdomain2) = current_number_neighbors(jdomain2) + 1
    1038        2710 :                domain_neighbor_list_excessive(jdomain2, current_number_neighbors(jdomain2)) = idomain2
    1039             :             END IF
    1040             :          END IF
    1041             :       END DO ! end loop over pairs of atoms
    1042         116 :       DEALLOCATE (global_list)
    1043             : 
    1044         926 :       max_domain_neighbors = MAXVAL(current_number_neighbors)
    1045         464 :       ALLOCATE (domain_neighbor_list(ndomains, max_domain_neighbors))
    1046        7164 :       domain_neighbor_list(:, :) = 0
    1047        7164 :       domain_neighbor_list(:, :) = domain_neighbor_list_excessive(:, 1:max_domain_neighbors)
    1048         116 :       DEALLOCATE (domain_neighbor_list_excessive)
    1049             : 
    1050         348 :       ALLOCATE (almo_scf_env%domain_map(ispin)%index1(ndomains))
    1051         348 :       ALLOCATE (almo_scf_env%domain_map(ispin)%pairs(max_domain_neighbors*ndomains, 2))
    1052       12824 :       almo_scf_env%domain_map(ispin)%pairs(:, :) = 0
    1053         926 :       almo_scf_env%domain_map(ispin)%index1(:) = 0
    1054             :       domain_map_local_entries = 0
    1055             : 
    1056             :       ! RZK-warning intermediate [0,1] quencher values are ill-defined
    1057             :       ! for molecules (not continuous and conceptually inadequate)
    1058             : 
    1059             :       ! O(N) loop over domain pairs
    1060         926 :       DO row = 1, nblkrows_tot
    1061        7156 :          DO col = 1, current_number_neighbors(row)
    1062        6230 :             tr = .FALSE.
    1063        6230 :             iblock_row = row
    1064        6230 :             iblock_col = domain_neighbor_list(row, col)
    1065             :             CALL dbcsr_get_stored_coordinates(almo_scf_env%quench_t(ispin), &
    1066        6230 :                                               iblock_row, iblock_col, hold)
    1067             : 
    1068        7040 :             IF (hold .EQ. mynode) THEN
    1069             : 
    1070             :                ! Translate indices of distribution blocks to indices of domain blocks
    1071             :                ! Rows are AOs
    1072        3115 :                domain_row = almo_scf_env%domain_index_of_ao_block(iblock_row)
    1073             :                ! Columns are electrons (i.e. MOs)
    1074        3115 :                domain_col = almo_scf_env%domain_index_of_mo_block(iblock_col)
    1075             : 
    1076        3115 :                SELECT CASE (almo_scf_env%constraint_type)
    1077             :                CASE (almo_constraint_block_diagonal)
    1078             : 
    1079           0 :                   block_active = .FALSE.
    1080             :                   ! type of electron groups
    1081           0 :                   IF (almo_scf_env%domain_layout_mos == almo_domain_layout_molecular) THEN
    1082             : 
    1083             :                      ! type of ao domains
    1084           0 :                      IF (almo_scf_env%domain_layout_aos == almo_domain_layout_molecular) THEN
    1085             : 
    1086             :                         ! ao domains are molecular / electron groups are molecular
    1087           0 :                         IF (domain_row == domain_col) THEN
    1088             :                            block_active = .TRUE.
    1089             :                         END IF
    1090             : 
    1091             :                      ELSE ! ao domains are atomic
    1092             : 
    1093             :                         ! ao domains are atomic / electron groups are molecular
    1094           0 :                         CPABORT("Illegal: atomic domains and molecular groups")
    1095             : 
    1096             :                      END IF
    1097             : 
    1098             :                   ELSE ! electron groups are atomic
    1099             : 
    1100             :                      ! type of ao domains
    1101           0 :                      IF (almo_scf_env%domain_layout_aos == almo_domain_layout_molecular) THEN
    1102             : 
    1103             :                         ! ao domains are molecular / electron groups are atomic
    1104           0 :                         CPABORT("Illegal: molecular domains and atomic groups")
    1105             : 
    1106             :                      ELSE
    1107             : 
    1108             :                         ! ao domains are atomic / electron groups are atomic
    1109           0 :                         IF (domain_row == domain_col) THEN
    1110             :                            block_active = .TRUE.
    1111             :                         END IF
    1112             : 
    1113             :                      END IF
    1114             : 
    1115             :                   END IF ! end type of electron groups
    1116             : 
    1117           0 :                   IF (block_active) THEN
    1118             : 
    1119           0 :                      NULLIFY (p_new_block)
    1120             :                      CALL dbcsr_reserve_block2d(almo_scf_env%quench_t(ispin), &
    1121           0 :                                                 iblock_row, iblock_col, p_new_block)
    1122           0 :                      CPASSERT(ASSOCIATED(p_new_block))
    1123           0 :                      p_new_block(:, :) = 1.0_dp
    1124             : 
    1125           0 :                      IF (domain_map_local_entries .GE. max_domain_neighbors*almo_scf_env%ndomains) THEN
    1126           0 :                         CPABORT("weird... max_domain_neighbors is exceeded")
    1127             :                      END IF
    1128           0 :                      almo_scf_env%domain_map(ispin)%pairs(domain_map_local_entries + 1, 1) = iblock_row
    1129           0 :                      almo_scf_env%domain_map(ispin)%pairs(domain_map_local_entries + 1, 2) = iblock_col
    1130           0 :                      domain_map_local_entries = domain_map_local_entries + 1
    1131             : 
    1132             :                   END IF
    1133             : 
    1134             :                CASE (almo_constraint_ao_overlap)
    1135             : 
    1136             :                   ! type of electron groups
    1137           0 :                   IF (almo_scf_env%domain_layout_mos == almo_domain_layout_molecular) THEN
    1138             : 
    1139             :                      ! type of ao domains
    1140           0 :                      IF (almo_scf_env%domain_layout_aos == almo_domain_layout_molecular) THEN
    1141             : 
    1142             :                         ! ao domains are molecular / electron groups are molecular
    1143             : 
    1144             :                         ! compute the maximum overlap between the atoms of the two molecules
    1145             :                         CALL dbcsr_get_block_p(matrix_s_sym, &
    1146           0 :                                                iblock_row, iblock_col, p_new_block, found)
    1147           0 :                         IF (found) THEN
    1148             :                            !   CPErrorMessage(cp_failure_level,routineP,"S block not found")
    1149             :                            !   CPPrecondition(.FALSE.,cp_failure_level,routineP,failure)
    1150           0 :                            overlap = MAXVAL(ABS(p_new_block))
    1151             :                         ELSE
    1152             :                            overlap = 0.0_dp
    1153             :                         END IF
    1154             : 
    1155             :                      ELSE ! ao domains are atomic
    1156             : 
    1157             :                         ! ao domains are atomic / electron groups are molecular
    1158             :                         ! overlap_between_atom_and_molecule(atom=domain_row,molecule=domain_col)
    1159           0 :                         CPABORT("atomic domains and molecular groups - NYI")
    1160             : 
    1161             :                      END IF
    1162             : 
    1163             :                   ELSE ! electron groups are atomic
    1164             : 
    1165             :                      ! type of ao domains
    1166           0 :                      IF (almo_scf_env%domain_layout_aos == almo_domain_layout_molecular) THEN
    1167             : 
    1168             :                         ! ao domains are molecular / electron groups are atomic
    1169             :                         ! overlap_between_atom_and_molecule(atom=domain_col,molecule=domain_row)
    1170           0 :                         CPABORT("molecular domains and atomic groups - NYI")
    1171             : 
    1172             :                      ELSE
    1173             : 
    1174             :                         ! ao domains are atomic / electron groups are atomic
    1175             :                         ! compute max overlap between atoms: domain_row and domain_col
    1176             :                         CALL dbcsr_get_block_p(matrix_s_sym, &
    1177           0 :                                                iblock_row, iblock_col, p_new_block, found)
    1178           0 :                         IF (found) THEN
    1179             :                            !   CPErrorMessage(cp_failure_level,routineP,"S block not found")
    1180             :                            !   CPPrecondition(.FALSE.,cp_failure_level,routineP,failure)
    1181           0 :                            overlap = MAXVAL(ABS(p_new_block))
    1182             :                         ELSE
    1183             :                            overlap = 0.0_dp
    1184             :                         END IF
    1185             : 
    1186             :                      END IF
    1187             : 
    1188             :                   END IF ! end type of electron groups
    1189             : 
    1190           0 :                   s0 = -LOG10(ABS(almo_scf_env%quencher_s0))
    1191           0 :                   s1 = -LOG10(ABS(almo_scf_env%quencher_s1))
    1192           0 :                   IF (overlap .EQ. 0.0_dp) THEN
    1193           0 :                      overlap = -LOG10(ABS(almo_scf_env%eps_filter)) + 100.0_dp
    1194             :                   ELSE
    1195           0 :                      overlap = -LOG10(overlap)
    1196             :                   END IF
    1197           0 :                   IF (s0 .LT. 0.0_dp) THEN
    1198           0 :                      CPABORT("S0 is less than zero")
    1199             :                   END IF
    1200           0 :                   IF (s1 .LE. 0.0_dp) THEN
    1201           0 :                      CPABORT("S1 is less than or equal to zero")
    1202             :                   END IF
    1203           0 :                   IF (s0 .GE. s1) THEN
    1204           0 :                      CPABORT("S0 is greater than or equal to S1")
    1205             :                   END IF
    1206             : 
    1207             :                   ! Fill in non-zero blocks if AOs are close to the electron center
    1208           0 :                   IF (overlap .LT. s1) THEN
    1209           0 :                      NULLIFY (p_new_block)
    1210             :                      CALL dbcsr_reserve_block2d(almo_scf_env%quench_t(ispin), &
    1211           0 :                                                 iblock_row, iblock_col, p_new_block)
    1212           0 :                      CPASSERT(ASSOCIATED(p_new_block))
    1213           0 :                      IF (overlap .LE. s0) THEN
    1214           0 :                         p_new_block(:, :) = 1.0_dp
    1215             :                         !WRITE(*,'(A15,2I7,3F8.3,E11.3)') "INTRA-BLOCKS: ",&
    1216             :                         !   iblock_col, iblock_row, s0, s1, overlap, p_new_block(1,1)
    1217             :                      ELSE
    1218           0 :                         p_new_block(:, :) = 1.0_dp/(1.0_dp + EXP(-(s0 - s1)/(s0 - overlap) - (s0 - s1)/(overlap - s1)))
    1219             :                         !WRITE(*,'(A15,2I7,3F8.3,E11.3)') "INTER-BLOCKS: ",&
    1220             :                         !   iblock_col, iblock_row, s0, s1, overlap, p_new_block(1,1)
    1221             :                      END IF
    1222             : 
    1223           0 :                      IF (ABS(p_new_block(1, 1)) .GT. ABS(almo_scf_env%eps_filter)) THEN
    1224           0 :                         IF (domain_map_local_entries .GE. max_domain_neighbors*almo_scf_env%ndomains) THEN
    1225           0 :                            CPABORT("weird... max_domain_neighbors is exceeded")
    1226             :                         END IF
    1227           0 :                         almo_scf_env%domain_map(ispin)%pairs(domain_map_local_entries + 1, 1) = iblock_row
    1228           0 :                         almo_scf_env%domain_map(ispin)%pairs(domain_map_local_entries + 1, 2) = iblock_col
    1229           0 :                         domain_map_local_entries = domain_map_local_entries + 1
    1230             :                      END IF
    1231             : 
    1232             :                   END IF
    1233             : 
    1234             :                CASE (almo_constraint_distance)
    1235             : 
    1236             :                   ! type of electron groups
    1237        3115 :                   IF (almo_scf_env%domain_layout_mos == almo_domain_layout_molecular) THEN
    1238             : 
    1239             :                      ! type of ao domains
    1240        3115 :                      IF (almo_scf_env%domain_layout_aos == almo_domain_layout_molecular) THEN
    1241             : 
    1242             :                         ! ao domains are molecular / electron groups are molecular
    1243             : 
    1244             :                         ! compute distance between molecules: domain_row and domain_col
    1245             :                         ! distance between molecules is defined as the smallest
    1246             :                         ! distance among all atom pairs
    1247        3115 :                         IF (domain_row == domain_col) THEN
    1248         405 :                            distance = 0.0_dp
    1249         405 :                            contact_atom_1 = first_atom_of_molecule(domain_row)
    1250         405 :                            contact_atom_2 = first_atom_of_molecule(domain_col)
    1251             :                         ELSE
    1252        2710 :                            distance_squared = 1.0E+100_dp
    1253        2710 :                            contact_atom_1 = -1
    1254        2710 :                            contact_atom_2 = -1
    1255        9034 :                            DO iatom = first_atom_of_molecule(domain_row), last_atom_of_molecule(domain_row)
    1256       26310 :                               DO jatom = first_atom_of_molecule(domain_col), last_atom_of_molecule(domain_col)
    1257       17276 :                                  rab(:) = pbc(particle_set(iatom)%r(:), particle_set(jatom)%r(:), cell)
    1258       17276 :                                  trial_distance_squared = rab(1)*rab(1) + rab(2)*rab(2) + rab(3)*rab(3)
    1259       23600 :                                  IF (trial_distance_squared .LT. distance_squared) THEN
    1260        6363 :                                     distance_squared = trial_distance_squared
    1261        6363 :                                     contact_atom_1 = iatom
    1262        6363 :                                     contact_atom_2 = jatom
    1263             :                                  END IF
    1264             :                               END DO ! jatom
    1265             :                            END DO ! iatom
    1266        2710 :                            CPASSERT(contact_atom_1 .GT. 0)
    1267        2710 :                            distance = SQRT(distance_squared)
    1268             :                         END IF
    1269             : 
    1270             :                      ELSE ! ao domains are atomic
    1271             : 
    1272             :                         ! ao domains are atomic / electron groups are molecular
    1273             :                         !distance_between_atom_and_molecule(atom=domain_row,molecule=domain_col)
    1274           0 :                         CPABORT("atomic domains and molecular groups - NYI")
    1275             : 
    1276             :                      END IF
    1277             : 
    1278             :                   ELSE ! electron groups are atomic
    1279             : 
    1280             :                      ! type of ao domains
    1281           0 :                      IF (almo_scf_env%domain_layout_aos == almo_domain_layout_molecular) THEN
    1282             : 
    1283             :                         ! ao domains are molecular / electron groups are atomic
    1284             :                         !distance_between_atom_and_molecule(atom=domain_col,molecule=domain_row)
    1285           0 :                         CPABORT("molecular domains and atomic groups - NYI")
    1286             : 
    1287             :                      ELSE
    1288             : 
    1289             :                         ! ao domains are atomic / electron groups are atomic
    1290             :                         ! compute distance between atoms: domain_row and domain_col
    1291           0 :                         rab(:) = pbc(particle_set(domain_row)%r(:), particle_set(domain_col)%r(:), cell)
    1292           0 :                         distance = SQRT(rab(1)*rab(1) + rab(2)*rab(2) + rab(3)*rab(3))
    1293           0 :                         contact_atom_1 = domain_row
    1294           0 :                         contact_atom_2 = domain_col
    1295             : 
    1296             :                      END IF
    1297             : 
    1298             :                   END IF ! end type of electron groups
    1299             : 
    1300             :                   ! get atomic radii to compute distance cutoff threshold
    1301        3115 :                   IF (almo_scf_env%quencher_radius_type == do_bondparm_covalent) THEN
    1302             :                      CALL get_atomic_kind(atomic_kind=particle_set(contact_atom_1)%atomic_kind, &
    1303           0 :                                           rcov=contact1_radius)
    1304             :                      CALL get_atomic_kind(atomic_kind=particle_set(contact_atom_2)%atomic_kind, &
    1305           0 :                                           rcov=contact2_radius)
    1306        3115 :                   ELSE IF (almo_scf_env%quencher_radius_type == do_bondparm_vdw) THEN
    1307             :                      CALL get_atomic_kind(atomic_kind=particle_set(contact_atom_1)%atomic_kind, &
    1308        3115 :                                           rvdw=contact1_radius)
    1309             :                      CALL get_atomic_kind(atomic_kind=particle_set(contact_atom_2)%atomic_kind, &
    1310        3115 :                                           rvdw=contact2_radius)
    1311             :                   ELSE
    1312           0 :                      CPABORT("Illegal quencher_radius_type")
    1313             :                   END IF
    1314        3115 :                   contact1_radius = cp_unit_to_cp2k(contact1_radius, "angstrom")
    1315        3115 :                   contact2_radius = cp_unit_to_cp2k(contact2_radius, "angstrom")
    1316             : 
    1317             :                   !RZK-warning the procedure is faulty for molecules:
    1318             :                   ! the closest contacts should be found using
    1319             :                   ! the element specific radii
    1320             : 
    1321             :                   ! compute inner and outer cutoff radii
    1322        3115 :                   r0 = almo_scf_env%quencher_r0_factor*(contact1_radius + contact2_radius)
    1323             :                   !+almo_scf_env%quencher_r0_shift
    1324        3115 :                   r1 = almo_scf_env%quencher_r1_factor*(contact1_radius + contact2_radius)
    1325             :                   !+almo_scf_env%quencher_r1_shift
    1326             : 
    1327        3115 :                   IF (r0 .LT. 0.0_dp) THEN
    1328           0 :                      CPABORT("R0 is less than zero")
    1329             :                   END IF
    1330        3115 :                   IF (r1 .LE. 0.0_dp) THEN
    1331           0 :                      CPABORT("R1 is less than or equal to zero")
    1332             :                   END IF
    1333        3115 :                   IF (r0 .GT. r1) THEN
    1334           0 :                      CPABORT("R0 is greater than or equal to R1")
    1335             :                   END IF
    1336             : 
    1337             :                   ! Fill in non-zero blocks if AOs are close to the electron center
    1338        3115 :                   IF (distance .LT. r1) THEN
    1339        2169 :                      NULLIFY (p_new_block)
    1340             :                      CALL dbcsr_reserve_block2d(almo_scf_env%quench_t(ispin), &
    1341        2169 :                                                 iblock_row, iblock_col, p_new_block)
    1342        2169 :                      CPASSERT(ASSOCIATED(p_new_block))
    1343        2169 :                      IF (distance .LE. r0) THEN
    1344      101401 :                         p_new_block(:, :) = 1.0_dp
    1345             :                         !WRITE(*,'(A15,2I7,5F8.3,E11.3)') "INTRA-BLOCKS: ",&
    1346             :                         !   iblock_col, iblock_row, contact1_radius,&
    1347             :                         !   contact2_radius, r0, r1, distance, p_new_block(1,1)
    1348             :                      ELSE
    1349             :                         ! remove the intermediate values from the quencher temporarily
    1350           0 :                         CPABORT("")
    1351           0 :                         p_new_block(:, :) = 1.0_dp/(1.0_dp + EXP((r1 - r0)/(r0 - distance) + (r1 - r0)/(r1 - distance)))
    1352             :                         !WRITE(*,'(A15,2I7,5F8.3,E11.3)') "INTER-BLOCKS: ",&
    1353             :                         !   iblock_col, iblock_row, contact1_radius,&
    1354             :                         !   contact2_radius, r0, r1, distance, p_new_block(1,1)
    1355             :                      END IF
    1356             : 
    1357        2169 :                      IF (ABS(p_new_block(1, 1)) .GT. ABS(almo_scf_env%eps_filter)) THEN
    1358        2169 :                         IF (domain_map_local_entries .GE. max_domain_neighbors*almo_scf_env%ndomains) THEN
    1359           0 :                            CPABORT("weird... max_domain_neighbors is exceeded")
    1360             :                         END IF
    1361        2169 :                         almo_scf_env%domain_map(ispin)%pairs(domain_map_local_entries + 1, 1) = iblock_row
    1362        2169 :                         almo_scf_env%domain_map(ispin)%pairs(domain_map_local_entries + 1, 2) = iblock_col
    1363        2169 :                         domain_map_local_entries = domain_map_local_entries + 1
    1364             :                      END IF
    1365             : 
    1366             :                   END IF
    1367             : 
    1368             :                CASE DEFAULT
    1369        3115 :                   CPABORT("Illegal constraint type")
    1370             :                END SELECT
    1371             : 
    1372             :             END IF ! mynode
    1373             : 
    1374             :          END DO
    1375             :       END DO ! end O(N) loop over pairs
    1376             : 
    1377         116 :       DEALLOCATE (domain_neighbor_list)
    1378         116 :       DEALLOCATE (current_number_neighbors)
    1379             : 
    1380         116 :       CALL dbcsr_finalize(almo_scf_env%quench_t(ispin))
    1381             :       !CALL dbcsr_scale(almo_scf_env%quench_t(ispin),&
    1382             :       !        almo_scf_env%envelope_amplitude)
    1383             :       CALL dbcsr_filter(almo_scf_env%quench_t(ispin), &
    1384         116 :                         almo_scf_env%eps_filter)
    1385             : 
    1386             :       ! check that both domain_map and quench_t have the same number of entries
    1387         116 :       nblks = dbcsr_get_num_blocks(almo_scf_env%quench_t(ispin))
    1388         116 :       IF (nblks .NE. domain_map_local_entries) THEN
    1389           0 :          CPABORT("number of blocks is wrong")
    1390             :       END IF
    1391             : 
    1392             :       ! first, communicate map sizes on the other nodes
    1393         348 :       ALLOCATE (domain_entries_cpu(nNodes), offset_for_cpu(nNodes))
    1394         116 :       CALL group%allgather(2*domain_map_local_entries, domain_entries_cpu)
    1395             : 
    1396             :       ! second, create
    1397         116 :       offset_for_cpu(1) = 0
    1398         232 :       DO iNode = 2, nNodes
    1399             :          offset_for_cpu(iNode) = offset_for_cpu(iNode - 1) + &
    1400         232 :                                  domain_entries_cpu(iNode - 1)
    1401             :       END DO
    1402         116 :       global_entries = offset_for_cpu(nNodes) + domain_entries_cpu(nNodes)
    1403             : 
    1404             :       ! communicate all entries
    1405         348 :       ALLOCATE (domain_map_global(global_entries))
    1406         460 :       ALLOCATE (domain_map_local(2*domain_map_local_entries))
    1407        2285 :       DO ientry = 1, domain_map_local_entries
    1408        2169 :          domain_map_local(2*(ientry - 1) + 1) = almo_scf_env%domain_map(ispin)%pairs(ientry, 1)
    1409        2285 :          domain_map_local(2*ientry) = almo_scf_env%domain_map(ispin)%pairs(ientry, 2)
    1410             :       END DO
    1411             :       CALL group%allgatherv(domain_map_local, domain_map_global, &
    1412         116 :                             domain_entries_cpu, offset_for_cpu)
    1413         116 :       DEALLOCATE (domain_entries_cpu, offset_for_cpu)
    1414         116 :       DEALLOCATE (domain_map_local)
    1415             : 
    1416         116 :       DEALLOCATE (almo_scf_env%domain_map(ispin)%index1)
    1417         116 :       DEALLOCATE (almo_scf_env%domain_map(ispin)%pairs)
    1418         232 :       ALLOCATE (almo_scf_env%domain_map(ispin)%index1(ndomains))
    1419         464 :       ALLOCATE (almo_scf_env%domain_map(ispin)%pairs(global_entries/2, 2))
    1420        9024 :       almo_scf_env%domain_map(ispin)%pairs(:, :) = 0
    1421         926 :       almo_scf_env%domain_map(ispin)%index1(:) = 0
    1422             : 
    1423             :       ! unpack the received data into a local variable
    1424             :       ! since we do not know the maximum global number of neighbors
    1425             :       ! try one. if fails increase the maximum number and try again
    1426             :       ! until it succeeds
    1427             :       max_neig = max_domain_neighbors
    1428             :       max_neig_fails = .TRUE.
    1429         232 :       max_neig_loop: DO WHILE (max_neig_fails)
    1430         464 :          ALLOCATE (domain_grid(almo_scf_env%ndomains, 0:max_neig))
    1431        8090 :          domain_grid(:, :) = 0
    1432             :          ! init the number of collected neighbors
    1433         926 :          domain_grid(:, 0) = 1
    1434             :          ! loop over the records
    1435         116 :          global_entries = global_entries/2
    1436        4454 :          DO ientry = 1, global_entries
    1437             :             ! get the center
    1438        4338 :             grid1 = domain_map_global(2*ientry)
    1439             :             ! get the neighbor
    1440        4338 :             ineig = domain_map_global(2*(ientry - 1) + 1)
    1441             :             ! check boundaries
    1442        4338 :             IF (domain_grid(grid1, 0) .GT. max_neig) THEN
    1443             :                ! this neighbor will overstep the boundaries
    1444             :                ! stop the trial and increase the max number of neighbors
    1445           0 :                DEALLOCATE (domain_grid)
    1446           0 :                max_neig = max_neig*2
    1447           0 :                CYCLE max_neig_loop
    1448             :             END IF
    1449             :             ! for the current center loop over the collected neighbors
    1450             :             ! to insert the current record in a numerical order
    1451             :             delayed_increment = .FALSE.
    1452       18944 :             DO igrid = 1, domain_grid(grid1, 0)
    1453             :                ! compare the current neighbor with that already in the 'book'
    1454       18944 :                IF (ineig .LT. domain_grid(grid1, igrid)) THEN
    1455             :                   ! if this one is smaller then insert it here and pick up the one
    1456             :                   ! from the book to continue inserting
    1457        3172 :                   neig_temp = ineig
    1458        3172 :                   ineig = domain_grid(grid1, igrid)
    1459        3172 :                   domain_grid(grid1, igrid) = neig_temp
    1460             :                ELSE
    1461       11434 :                   IF (domain_grid(grid1, igrid) .EQ. 0) THEN
    1462             :                      ! got the empty slot now - insert the record
    1463        4338 :                      domain_grid(grid1, igrid) = ineig
    1464             :                      ! increase the record counter but do it outside the loop
    1465        4338 :                      delayed_increment = .TRUE.
    1466             :                   END IF
    1467             :                END IF
    1468             :             END DO
    1469        4454 :             IF (delayed_increment) THEN
    1470        4338 :                domain_grid(grid1, 0) = domain_grid(grid1, 0) + 1
    1471             :             ELSE
    1472             :                ! should not be here - all records must be inserted
    1473           0 :                CPABORT("all records must be inserted")
    1474             :             END IF
    1475             :          END DO
    1476         116 :          max_neig_fails = .FALSE.
    1477             :       END DO max_neig_loop
    1478         116 :       DEALLOCATE (domain_map_global)
    1479             : 
    1480         116 :       ientry = 1
    1481         926 :       DO idomain = 1, almo_scf_env%ndomains
    1482        5148 :          DO ineig = 1, domain_grid(idomain, 0) - 1
    1483        4338 :             almo_scf_env%domain_map(ispin)%pairs(ientry, 1) = domain_grid(idomain, ineig)
    1484        4338 :             almo_scf_env%domain_map(ispin)%pairs(ientry, 2) = idomain
    1485        5148 :             ientry = ientry + 1
    1486             :          END DO
    1487         926 :          almo_scf_env%domain_map(ispin)%index1(idomain) = ientry
    1488             :       END DO
    1489         116 :       DEALLOCATE (domain_grid)
    1490             : 
    1491             :       !ENDDO ! ispin
    1492         116 :       IF (almo_scf_env%nspins .EQ. 2) THEN
    1493             :          CALL dbcsr_copy(almo_scf_env%quench_t(2), &
    1494           0 :                          almo_scf_env%quench_t(1))
    1495             :          almo_scf_env%domain_map(2)%pairs(:, :) = &
    1496           0 :             almo_scf_env%domain_map(1)%pairs(:, :)
    1497             :          almo_scf_env%domain_map(2)%index1(:) = &
    1498           0 :             almo_scf_env%domain_map(1)%index1(:)
    1499             :       END IF
    1500             : 
    1501         116 :       CALL dbcsr_release(matrix_s_sym)
    1502             : 
    1503         116 :       IF (almo_scf_env%domain_layout_mos == almo_domain_layout_molecular .OR. &
    1504             :           almo_scf_env%domain_layout_aos == almo_domain_layout_molecular) THEN
    1505         116 :          DEALLOCATE (first_atom_of_molecule)
    1506         116 :          DEALLOCATE (last_atom_of_molecule)
    1507             :       END IF
    1508             : 
    1509             :       !mynode = dbcsr_mp_mynode(dbcsr_distribution_mp(&
    1510             :       !   dbcsr_distribution(almo_scf_env%quench_t(ispin))))
    1511             :       !nblkrows_tot = dbcsr_nblkrows_total(almo_scf_env%quench_t(ispin))
    1512             :       !nblkcols_tot = dbcsr_nblkcols_total(almo_scf_env%quench_t(ispin))
    1513             :       !DO row = 1, nblkrows_tot
    1514             :       !   DO col = 1, nblkcols_tot
    1515             :       !      tr = .FALSE.
    1516             :       !      iblock_row = row
    1517             :       !      iblock_col = col
    1518             :       !      CALL dbcsr_get_stored_coordinates(almo_scf_env%quench_t(ispin),&
    1519             :       !              iblock_row, iblock_col, tr, hold)
    1520             :       !      CALL dbcsr_get_block_p(almo_scf_env%quench_t(ispin),&
    1521             :       !              row, col, p_new_block, found)
    1522             :       !      write(*,*) "RST_NOTE:", mynode, row, col, hold, found
    1523             :       !   ENDDO
    1524             :       !ENDDO
    1525             : 
    1526         116 :       CALL timestop(handle)
    1527             : 
    1528         348 :    END SUBROUTINE almo_scf_construct_quencher
    1529             : 
    1530             : ! *****************************************************************************
    1531             : !> \brief Compute matrix W (energy-weighted density matrix) that is needed
    1532             : !>        for the evaluation of forces
    1533             : !> \param matrix_w ...
    1534             : !> \param almo_scf_env ...
    1535             : !> \par History
    1536             : !>       2015.03 created [Rustam Z. Khaliullin]
    1537             : !> \author Rustam Z. Khaliullin
    1538             : ! **************************************************************************************************
    1539          66 :    SUBROUTINE calculate_w_matrix_almo(matrix_w, almo_scf_env)
    1540             :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_w
    1541             :       TYPE(almo_scf_env_type)                            :: almo_scf_env
    1542             : 
    1543             :       CHARACTER(len=*), PARAMETER :: routineN = 'calculate_w_matrix_almo'
    1544             : 
    1545             :       INTEGER                                            :: handle, ispin
    1546             :       REAL(KIND=dp)                                      :: scaling
    1547             :       TYPE(dbcsr_type)                                   :: tmp_nn1, tmp_no1, tmp_oo1, tmp_oo2
    1548             : 
    1549          66 :       CALL timeset(routineN, handle)
    1550             : 
    1551          66 :       IF (almo_scf_env%nspins == 1) THEN
    1552          66 :          scaling = 2.0_dp
    1553             :       ELSE
    1554           0 :          scaling = 1.0_dp
    1555             :       END IF
    1556             : 
    1557         132 :       DO ispin = 1, almo_scf_env%nspins
    1558             : 
    1559             :          CALL dbcsr_create(tmp_nn1, template=almo_scf_env%matrix_s(1), &
    1560          66 :                            matrix_type=dbcsr_type_no_symmetry)
    1561             :          CALL dbcsr_create(tmp_no1, template=almo_scf_env%matrix_t(ispin), &
    1562          66 :                            matrix_type=dbcsr_type_no_symmetry)
    1563             :          CALL dbcsr_create(tmp_oo1, template=almo_scf_env%matrix_sigma_inv(ispin), &
    1564          66 :                            matrix_type=dbcsr_type_no_symmetry)
    1565             :          CALL dbcsr_create(tmp_oo2, template=almo_scf_env%matrix_sigma_inv(ispin), &
    1566          66 :                            matrix_type=dbcsr_type_no_symmetry)
    1567             : 
    1568          66 :          CALL dbcsr_copy(tmp_nn1, almo_scf_env%matrix_ks(ispin))
    1569             :          ! 1. TMP_NO1=F.T
    1570             :          CALL dbcsr_multiply("N", "N", scaling, tmp_nn1, almo_scf_env%matrix_t(ispin), &
    1571          66 :                              0.0_dp, tmp_no1, filter_eps=almo_scf_env%eps_filter)
    1572             :          ! 2. TMP_OO1=T^(tr).TMP_NO1=T^(tr).(FT)
    1573             :          CALL dbcsr_multiply("T", "N", 1.0_dp, almo_scf_env%matrix_t(ispin), tmp_no1, &
    1574          66 :                              0.0_dp, tmp_oo1, filter_eps=almo_scf_env%eps_filter)
    1575             :          ! 3. TMP_OO2=TMP_OO1.siginv=(T^(tr)FT).siginv
    1576             :          CALL dbcsr_multiply("N", "N", 1.0_dp, tmp_oo1, almo_scf_env%matrix_sigma_inv(ispin), &
    1577          66 :                              0.0_dp, tmp_oo2, filter_eps=almo_scf_env%eps_filter)
    1578             :          ! 4. TMP_OO1=siginv.TMP_OO2=siginv.(T^(tr)FTsiginv)
    1579             :          CALL dbcsr_multiply("N", "N", 1.0_dp, almo_scf_env%matrix_sigma_inv(ispin), tmp_oo2, &
    1580          66 :                              0.0_dp, tmp_oo1, filter_eps=almo_scf_env%eps_filter)
    1581             :          ! 5. TMP_NO1=T.TMP_OO1.=T.(siginvT^(tr)FTsiginv)
    1582             :          CALL dbcsr_multiply("N", "N", 1.0_dp, almo_scf_env%matrix_t(ispin), tmp_oo1, &
    1583          66 :                              0.0_dp, tmp_no1, filter_eps=almo_scf_env%eps_filter)
    1584             :          ! 6. TMP_NN1=TMP_NO1.T^(tr)=(TsiginvT^(tr)FTsiginv).T^(tr)=RFR
    1585             :          CALL dbcsr_multiply("N", "T", 1.0_dp, tmp_no1, almo_scf_env%matrix_t(ispin), &
    1586          66 :                              0.0_dp, tmp_nn1, filter_eps=almo_scf_env%eps_filter)
    1587          66 :          CALL matrix_almo_to_qs(tmp_nn1, matrix_w(ispin)%matrix, almo_scf_env%mat_distr_aos)
    1588             : 
    1589          66 :          CALL dbcsr_release(tmp_nn1)
    1590          66 :          CALL dbcsr_release(tmp_no1)
    1591          66 :          CALL dbcsr_release(tmp_oo1)
    1592         132 :          CALL dbcsr_release(tmp_oo2)
    1593             : 
    1594             :       END DO
    1595             : 
    1596          66 :       CALL timestop(handle)
    1597             : 
    1598          66 :    END SUBROUTINE calculate_w_matrix_almo
    1599             : 
    1600             : END MODULE almo_scf_qs
    1601             : 

Generated by: LCOV version 1.15