(git:1f285aa)
qs_atomic_block.F
Go to the documentation of this file.
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 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 ! **************************************************************************************************
16  USE atomic_kind_types, ONLY: atomic_kind_type,&
18  USE dbcsr_api, ONLY: &
19  dbcsr_add_on_diag, dbcsr_dot, dbcsr_get_info, dbcsr_iterator_blocks_left, &
20  dbcsr_iterator_next_block, dbcsr_iterator_start, dbcsr_iterator_stop, dbcsr_iterator_type, &
21  dbcsr_p_type, dbcsr_scale, dbcsr_set, dbcsr_type
22  USE kinds, ONLY: dp
23  USE message_passing, ONLY: mp_para_env_type
24  USE qs_kind_types, ONLY: qs_kind_type
25 #include "./base/base_uses.f90"
26 
27  IMPLICIT NONE
28 
29  PRIVATE
30 
31  CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_atomic_block'
32 
34 
35  TYPE atom_matrix_type
36  REAL(KIND=dp), DIMENSION(:, :, :), POINTER :: mat
37  END TYPE atom_matrix_type
38 
39 CONTAINS
40 
41 ! **************************************************************************************************
42 !> \brief returns a block diagonal density matrix. Blocks correspond to the atomic densities.
43 !> \param pmatrix ...
44 !> \param matrix_s ...
45 !> \param atomic_kind_set ...
46 !> \param qs_kind_set ...
47 !> \param nspin ...
48 !> \param nelectron_spin ...
49 !> \param ounit ...
50 !> \param para_env ...
51 ! **************************************************************************************************
52  SUBROUTINE calculate_atomic_block_dm(pmatrix, matrix_s, atomic_kind_set, &
53  qs_kind_set, nspin, nelectron_spin, ounit, para_env)
54  TYPE(dbcsr_p_type), DIMENSION(:), INTENT(INOUT) :: pmatrix
55  TYPE(dbcsr_type), INTENT(INOUT) :: matrix_s
56  TYPE(atomic_kind_type), DIMENSION(:), POINTER :: atomic_kind_set
57  TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
58  INTEGER, INTENT(IN) :: nspin
59  INTEGER, DIMENSION(:), INTENT(IN) :: nelectron_spin
60  INTEGER, INTENT(IN) :: ounit
61  TYPE(mp_para_env_type) :: para_env
62 
63  CHARACTER(LEN=*), PARAMETER :: routinen = 'calculate_atomic_block_dm'
64 
65  INTEGER :: blk, handle, icol, ikind, irow, ispin, &
66  nc, nkind, nocc(2)
67  INTEGER, ALLOCATABLE, DIMENSION(:) :: kind_of
68  INTEGER, ALLOCATABLE, DIMENSION(:, :) :: nok
69  REAL(dp), DIMENSION(:, :), POINTER :: pdata
70  REAL(kind=dp) :: rds, rscale, trps1
71  TYPE(atom_matrix_type), ALLOCATABLE, DIMENSION(:) :: pmat
72  TYPE(atomic_kind_type), POINTER :: atomic_kind
73  TYPE(dbcsr_iterator_type) :: iter
74  TYPE(dbcsr_type), POINTER :: matrix_p
75  TYPE(qs_kind_type), POINTER :: qs_kind
76 
77  CALL timeset(routinen, handle)
78 
79  nkind = SIZE(atomic_kind_set)
80  CALL get_atomic_kind_set(atomic_kind_set=atomic_kind_set, kind_of=kind_of)
81  ALLOCATE (pmat(nkind))
82  ALLOCATE (nok(2, nkind))
83 
84  ! precompute the atomic blocks corresponding to spherical atoms
85  DO ikind = 1, nkind
86  atomic_kind => atomic_kind_set(ikind)
87  qs_kind => qs_kind_set(ikind)
88  NULLIFY (pmat(ikind)%mat)
89  IF (ounit > 0) THEN
90  WRITE (unit=ounit, fmt="(/,T2,A)") &
91  "Guess for atomic kind: "//trim(atomic_kind%name)
92  END IF
93  CALL calculate_atomic_orbitals(atomic_kind, qs_kind, iunit=ounit, &
94  pmat=pmat(ikind)%mat, nocc=nocc)
95  nok(1:2, ikind) = nocc(1:2)
96  END DO
97 
98  rscale = 1.0_dp
99  IF (nspin == 2) rscale = 0.5_dp
100 
101  DO ispin = 1, nspin
102  IF ((ounit > 0) .AND. (nspin > 1)) THEN
103  WRITE (unit=ounit, fmt="(/,T2,A,I0)") "Spin ", ispin
104  END IF
105 
106  matrix_p => pmatrix(ispin)%matrix
107  CALL dbcsr_set(matrix_p, 0.0_dp)
108 
109  nocc(ispin) = 0
110  CALL dbcsr_iterator_start(iter, matrix_p)
111  DO WHILE (dbcsr_iterator_blocks_left(iter))
112  CALL dbcsr_iterator_next_block(iter, irow, icol, pdata, blk)
113  ikind = kind_of(irow)
114  IF (icol .EQ. irow) THEN
115  IF (ispin == 1) THEN
116  pdata(:, :) = pmat(ikind)%mat(:, :, 1)*rscale + &
117  pmat(ikind)%mat(:, :, 2)*rscale
118  ELSE
119  pdata(:, :) = pmat(ikind)%mat(:, :, 1)*rscale - &
120  pmat(ikind)%mat(:, :, 2)*rscale
121  END IF
122  nocc(ispin) = nocc(ispin) + nok(ispin, ikind)
123  END IF
124  END DO
125  CALL dbcsr_iterator_stop(iter)
126 
127  CALL dbcsr_dot(matrix_p, matrix_s, trps1)
128  rds = 0.0_dp
129  ! could be a ghost-atoms-only simulation
130  IF (nelectron_spin(ispin) > 0) THEN
131  rds = real(nelectron_spin(ispin), dp)/trps1
132  END IF
133  CALL dbcsr_scale(matrix_p, rds)
134 
135  IF (ounit > 0) THEN
136  IF (nspin > 1) THEN
137  WRITE (unit=ounit, fmt="(T2,A,I1)") &
138  "Re-scaling the density matrix to get the right number of electrons for spin ", ispin
139  ELSE
140  WRITE (unit=ounit, fmt="(T2,A)") &
141  "Re-scaling the density matrix to get the right number of electrons"
142  END IF
143  WRITE (ounit, '(T19,A,T44,A,T67,A)') "# Electrons", "Trace(P)", "Scaling factor"
144  WRITE (ounit, '(T20,I10,T40,F12.3,T67,F14.3)') nelectron_spin(ispin), trps1, rds
145  END IF
146 
147  IF (nspin > 1) THEN
148  CALL para_env%sum(nocc)
149  IF (nelectron_spin(ispin) > nocc(ispin)) THEN
150  rds = 0.99_dp
151  CALL dbcsr_scale(matrix_p, rds)
152  rds = (1.0_dp - rds)*nelectron_spin(ispin)
153  CALL dbcsr_get_info(matrix_p, nfullcols_total=nc)
154  rds = rds/real(nc, kind=dp)
155  CALL dbcsr_add_on_diag(matrix_p, rds)
156  IF (ounit > 0) THEN
157  WRITE (unit=ounit, fmt="(T4,A,/,T4,A,T59,F20.12)") &
158  "More MOs than initial guess orbitals detected", &
159  "Add constant to diagonal elements ", rds
160  END IF
161  END IF
162  END IF
163 
164  END DO
165 
166  DO ikind = 1, nkind
167  IF (ASSOCIATED(pmat(ikind)%mat)) THEN
168  DEALLOCATE (pmat(ikind)%mat)
169  END IF
170  END DO
171  DEALLOCATE (pmat)
172 
173  DEALLOCATE (kind_of, nok)
174 
175  CALL timestop(handle)
176 
177  END SUBROUTINE calculate_atomic_block_dm
178 
179 END MODULE qs_atomic_block
calculate the orbitals for a given atomic kind type
subroutine, public calculate_atomic_orbitals(atomic_kind, qs_kind, agrid, iunit, pmat, fmat, density, wavefunction, wfninfo, confine, xc_section, nocc)
...
Define the atomic kind types and their sub types.
subroutine, public get_atomic_kind_set(atomic_kind_set, atom_of_kind, kind_of, natom_of_kind, maxatom, natom, nshell, fist_potential_present, shell_present, shell_adiabatic, shell_check_distance, damping_present)
Get attributes of an atomic kind set.
Defines the basic variable types.
Definition: kinds.F:23
integer, parameter, public dp
Definition: kinds.F:34
Interface to the message passing library MPI.
Routine to return block diagonal density matrix. Blocks correspond to the atomic densities.
subroutine, public calculate_atomic_block_dm(pmatrix, matrix_s, atomic_kind_set, qs_kind_set, nspin, nelectron_spin, ounit, para_env)
returns a block diagonal density matrix. Blocks correspond to the atomic densities.
Define the quickstep kind type and their sub types.
Definition: qs_kind_types.F:23