LCOV - code coverage report
Current view: top level - src - qs_atomic_block.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:b4bd748) Lines: 67 68 98.5 %
Date: 2025-03-09 07:56:22 Functions: 1 2 50.0 %

          Line data    Source code
       1             : !--------------------------------------------------------------------------------------------------!
       2             : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3             : !   Copyright 2000-2025 CP2K developers group <https://cp2k.org>                                   !
       4             : !                                                                                                  !
       5             : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6             : !--------------------------------------------------------------------------------------------------!
       7             : 
       8             : ! **************************************************************************************************
       9             : !> \brief Routine to return block diagonal density matrix. Blocks correspond to the atomic densities
      10             : !> \par History
      11             : !>       2006.03 Moved here from qs_scf.F [Joost VandeVondele]
      12             : !>       2022.05 split from qs_initial_guess.F to break circular dependency [Harald Forbert]
      13             : ! **************************************************************************************************
      14             : MODULE qs_atomic_block
      15             :    USE atom_kind_orbitals,              ONLY: calculate_atomic_orbitals
      16             :    USE atomic_kind_types,               ONLY: atomic_kind_type,&
      17             :                                               get_atomic_kind_set
      18             :    USE cp_dbcsr_api,                    ONLY: &
      19             :         dbcsr_get_info, dbcsr_iterator_blocks_left, dbcsr_iterator_next_block, &
      20             :         dbcsr_iterator_start, dbcsr_iterator_stop, dbcsr_iterator_type, dbcsr_p_type, dbcsr_scale, &
      21             :         dbcsr_set, dbcsr_type
      22             :    USE cp_dbcsr_contrib,                ONLY: dbcsr_add_on_diag,&
      23             :                                               dbcsr_dot
      24             :    USE kinds,                           ONLY: dp
      25             :    USE message_passing,                 ONLY: mp_para_env_type
      26             :    USE qs_kind_types,                   ONLY: qs_kind_type
      27             : #include "./base/base_uses.f90"
      28             : 
      29             :    IMPLICIT NONE
      30             : 
      31             :    PRIVATE
      32             : 
      33             :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_atomic_block'
      34             : 
      35             :    PUBLIC ::  calculate_atomic_block_dm
      36             : 
      37             :    TYPE atom_matrix_type
      38             :       REAL(KIND=dp), DIMENSION(:, :, :), POINTER   :: mat => NULL()
      39             :    END TYPE atom_matrix_type
      40             : 
      41             : CONTAINS
      42             : 
      43             : ! **************************************************************************************************
      44             : !> \brief returns a block diagonal density matrix. Blocks correspond to the atomic densities.
      45             : !> \param pmatrix ...
      46             : !> \param matrix_s ...
      47             : !> \param atomic_kind_set ...
      48             : !> \param qs_kind_set ...
      49             : !> \param nspin ...
      50             : !> \param nelectron_spin ...
      51             : !> \param ounit ...
      52             : !> \param para_env ...
      53             : ! **************************************************************************************************
      54        4607 :    SUBROUTINE calculate_atomic_block_dm(pmatrix, matrix_s, atomic_kind_set, &
      55        4607 :                                         qs_kind_set, nspin, nelectron_spin, ounit, para_env)
      56             :       TYPE(dbcsr_p_type), DIMENSION(:), INTENT(INOUT)    :: pmatrix
      57             :       TYPE(dbcsr_type), INTENT(INOUT)                    :: matrix_s
      58             :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
      59             :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
      60             :       INTEGER, INTENT(IN)                                :: nspin
      61             :       INTEGER, DIMENSION(:), INTENT(IN)                  :: nelectron_spin
      62             :       INTEGER, INTENT(IN)                                :: ounit
      63             :       TYPE(mp_para_env_type)                             :: para_env
      64             : 
      65             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'calculate_atomic_block_dm'
      66             : 
      67             :       INTEGER                                            :: handle, icol, ikind, irow, ispin, nc, &
      68             :                                                             nkind, nocc(2)
      69        4607 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: kind_of
      70        4607 :       INTEGER, ALLOCATABLE, DIMENSION(:, :)              :: nok
      71        4607 :       REAL(dp), DIMENSION(:, :), POINTER                 :: pdata
      72             :       REAL(KIND=dp)                                      :: rds, rscale, trps1
      73        4607 :       TYPE(atom_matrix_type), ALLOCATABLE, DIMENSION(:)  :: pmat
      74             :       TYPE(atomic_kind_type), POINTER                    :: atomic_kind
      75             :       TYPE(dbcsr_iterator_type)                          :: iter
      76             :       TYPE(dbcsr_type), POINTER                          :: matrix_p
      77             :       TYPE(qs_kind_type), POINTER                        :: qs_kind
      78             : 
      79        4607 :       CALL timeset(routineN, handle)
      80             : 
      81        4607 :       nkind = SIZE(atomic_kind_set)
      82        4607 :       CALL get_atomic_kind_set(atomic_kind_set=atomic_kind_set, kind_of=kind_of)
      83       22127 :       ALLOCATE (pmat(nkind))
      84       13821 :       ALLOCATE (nok(2, nkind))
      85             : 
      86             :       ! precompute the atomic blocks corresponding to spherical atoms
      87       12913 :       DO ikind = 1, nkind
      88        8306 :          atomic_kind => atomic_kind_set(ikind)
      89        8306 :          qs_kind => qs_kind_set(ikind)
      90        8306 :          NULLIFY (pmat(ikind)%mat)
      91        8306 :          IF (ounit > 0) THEN
      92             :             WRITE (UNIT=ounit, FMT="(/,T2,A)") &
      93        2011 :                "Guess for atomic kind: "//TRIM(atomic_kind%name)
      94             :          END IF
      95             :          CALL calculate_atomic_orbitals(atomic_kind, qs_kind, iunit=ounit, &
      96        8306 :                                         pmat=pmat(ikind)%mat, nocc=nocc)
      97       29525 :          nok(1:2, ikind) = nocc(1:2)
      98             :       END DO
      99             : 
     100        4607 :       rscale = 1.0_dp
     101        4607 :       IF (nspin == 2) rscale = 0.5_dp
     102             : 
     103       10173 :       DO ispin = 1, nspin
     104        5566 :          IF ((ounit > 0) .AND. (nspin > 1)) THEN
     105         504 :             WRITE (UNIT=ounit, FMT="(/,T2,A,I0)") "Spin ", ispin
     106             :          END IF
     107             : 
     108        5566 :          matrix_p => pmatrix(ispin)%matrix
     109        5566 :          CALL dbcsr_set(matrix_p, 0.0_dp)
     110             : 
     111        5566 :          nocc(ispin) = 0
     112        5566 :          CALL dbcsr_iterator_start(iter, matrix_p)
     113       83489 :          DO WHILE (dbcsr_iterator_blocks_left(iter))
     114       77923 :             CALL dbcsr_iterator_next_block(iter, irow, icol, pdata)
     115       77923 :             ikind = kind_of(irow)
     116       83489 :             IF (icol .EQ. irow) THEN
     117       11784 :                IF (ispin == 1) THEN
     118             :                   pdata(:, :) = pmat(ikind)%mat(:, :, 1)*rscale + &
     119     1017946 :                                 pmat(ikind)%mat(:, :, 2)*rscale
     120             :                ELSE
     121             :                   pdata(:, :) = pmat(ikind)%mat(:, :, 1)*rscale - &
     122      174908 :                                 pmat(ikind)%mat(:, :, 2)*rscale
     123             :                END IF
     124       11784 :                nocc(ispin) = nocc(ispin) + nok(ispin, ikind)
     125             :             END IF
     126             :          END DO
     127        5566 :          CALL dbcsr_iterator_stop(iter)
     128             : 
     129        5566 :          CALL dbcsr_dot(matrix_p, matrix_s, trps1)
     130        5566 :          rds = 0.0_dp
     131             :          ! could be a ghost-atoms-only simulation
     132        5566 :          IF (nelectron_spin(ispin) > 0) THEN
     133        5434 :             rds = REAL(nelectron_spin(ispin), dp)/trps1
     134             :          END IF
     135        5566 :          CALL dbcsr_scale(matrix_p, rds)
     136             : 
     137        5566 :          IF (ounit > 0) THEN
     138        1386 :             IF (nspin > 1) THEN
     139             :                WRITE (UNIT=ounit, FMT="(T2,A,I1)") &
     140         504 :                   "Re-scaling the density matrix to get the right number of electrons for spin ", ispin
     141             :             ELSE
     142             :                WRITE (UNIT=ounit, FMT="(T2,A)") &
     143         882 :                   "Re-scaling the density matrix to get the right number of electrons"
     144             :             END IF
     145        1386 :             WRITE (ounit, '(T19,A,T44,A,T67,A)') "# Electrons", "Trace(P)", "Scaling factor"
     146        1386 :             WRITE (ounit, '(T20,I10,T40,F12.3,T67,F14.3)') nelectron_spin(ispin), trps1, rds
     147             :          END IF
     148             : 
     149       21305 :          IF (nspin > 1) THEN
     150        1918 :             CALL para_env%sum(nocc)
     151        1918 :             IF (nelectron_spin(ispin) > nocc(ispin)) THEN
     152           2 :                rds = 0.99_dp
     153           2 :                CALL dbcsr_scale(matrix_p, rds)
     154           2 :                rds = (1.0_dp - rds)*nelectron_spin(ispin)
     155           2 :                CALL dbcsr_get_info(matrix_p, nfullcols_total=nc)
     156           2 :                rds = rds/REAL(nc, KIND=dp)
     157           2 :                CALL dbcsr_add_on_diag(matrix_p, rds)
     158           2 :                IF (ounit > 0) THEN
     159             :                   WRITE (UNIT=ounit, FMT="(T4,A,/,T4,A,T59,F20.12)") &
     160           1 :                      "More MOs than initial guess orbitals detected", &
     161           2 :                      "Add constant to diagonal elements ", rds
     162             :                END IF
     163             :             END IF
     164             :          END IF
     165             : 
     166             :       END DO
     167             : 
     168       12913 :       DO ikind = 1, nkind
     169       12913 :          IF (ASSOCIATED(pmat(ikind)%mat)) THEN
     170        8306 :             DEALLOCATE (pmat(ikind)%mat)
     171             :          END IF
     172             :       END DO
     173        4607 :       DEALLOCATE (pmat)
     174             : 
     175        4607 :       DEALLOCATE (kind_of, nok)
     176             : 
     177        4607 :       CALL timestop(handle)
     178             : 
     179        4607 :    END SUBROUTINE calculate_atomic_block_dm
     180             : 
     181           0 : END MODULE qs_atomic_block

Generated by: LCOV version 1.15