(git:e7e05ae)
pao_param_fock.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 Common framework for using eigenvectors of a Fock matrix as PAO basis.
10 !> \author Ole Schuett
11 ! **************************************************************************************************
13  USE dbcsr_api, ONLY: dbcsr_get_block_p,&
14  dbcsr_get_info
15  USE kinds, ONLY: dp
16  USE mathlib, ONLY: diamat_all
17  USE pao_types, ONLY: pao_env_type
18 #include "./base/base_uses.f90"
19 
20  IMPLICIT NONE
21 
22  PRIVATE
23 
24  CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'pao_param_fock'
25 
26  PUBLIC :: pao_calc_u_block_fock
27 
28 CONTAINS
29 
30 ! **************************************************************************************************
31 !> \brief Calculate new matrix U and optinally its gradient G
32 !> \param pao ...
33 !> \param iatom ...
34 !> \param V ...
35 !> \param U ...
36 !> \param penalty ...
37 !> \param gap ...
38 !> \param evals ...
39 !> \param M1 ...
40 !> \param G ...
41 ! **************************************************************************************************
42  SUBROUTINE pao_calc_u_block_fock(pao, iatom, V, U, penalty, gap, evals, M1, G)
43  TYPE(pao_env_type), POINTER :: pao
44  INTEGER, INTENT(IN) :: iatom
45  REAL(dp), DIMENSION(:, :), POINTER :: v, u
46  REAL(dp), INTENT(INOUT), OPTIONAL :: penalty
47  REAL(dp), INTENT(OUT) :: gap
48  REAL(dp), DIMENSION(:), INTENT(OUT), OPTIONAL :: evals
49  REAL(dp), DIMENSION(:, :), OPTIONAL, POINTER :: m1, g
50 
51  CHARACTER(len=*), PARAMETER :: routinen = 'pao_calc_U_block_fock'
52 
53  INTEGER :: handle, i, j, m, n
54  INTEGER, DIMENSION(:), POINTER :: blk_sizes_pao, blk_sizes_pri
55  LOGICAL :: found
56  REAL(dp) :: alpha, beta, denom, diff
57  REAL(dp), DIMENSION(:), POINTER :: h_evals
58  REAL(dp), DIMENSION(:, :), POINTER :: block_n, d1, d2, h, h0, h_evecs, m2, m3, &
59  m4, m5
60 
61  CALL timeset(routinen, handle)
62 
63  CALL dbcsr_get_block_p(matrix=pao%matrix_H0, row=iatom, col=iatom, block=h0, found=found)
64  cpassert(ASSOCIATED(h0))
65  CALL dbcsr_get_block_p(matrix=pao%matrix_N_diag, row=iatom, col=iatom, block=block_n, found=found)
66  cpassert(ASSOCIATED(block_n))
67  IF (maxval(abs(v - transpose(v))) > 1e-14_dp) cpabort("Expect symmetric matrix")
68 
69  ! figure out basis sizes
70  CALL dbcsr_get_info(pao%matrix_Y, row_blk_size=blk_sizes_pri, col_blk_size=blk_sizes_pao)
71  n = blk_sizes_pri(iatom) ! size of primary basis
72  m = blk_sizes_pao(iatom) ! size of pao basis
73 
74  ! calculate H in the orthonormal basis
75  ALLOCATE (h(n, n))
76  h = matmul(matmul(block_n, h0 + v), block_n)
77 
78  ! diagonalize H
79  ALLOCATE (h_evals(n), h_evecs(n, n))
80  h_evecs = h
81  CALL diamat_all(h_evecs, h_evals)
82 
83  ! the eigenvectors of H become the rotation matrix U
84  u = h_evecs
85 
86  ! copy eigenvectors around the gap from H_evals into evals array
87  IF (PRESENT(evals)) THEN
88  cpassert(mod(SIZE(evals), 2) == 0) ! gap will be exactely in the middle
89  i = SIZE(evals)/2
90  j = min(m, i)
91  evals(1 + i - j:i) = h_evals(1 + m - j:m) ! eigenvalues below gap
92  j = min(n - m, i)
93  evals(i:i + j) = h_evals(m:m + j) ! eigenvalues above gap
94  END IF
95 
96  ! calculate homo-lumo gap (it's useful for detecting numerical issues)
97  gap = huge(dp)
98  IF (m < n) & ! catch special case n==m
99  gap = h_evals(m + 1) - h_evals(m)
100 
101  IF (PRESENT(penalty)) THEN
102  ! penalty terms: occupied and virtual eigenvalues repel each other
103  alpha = pao%penalty_strength
104  beta = pao%penalty_dist
105  DO i = 1, m
106  DO j = m + 1, n
107  diff = h_evals(i) - h_evals(j)
108  penalty = penalty + alpha*exp(-(diff/beta)**2)
109  END DO
110  END DO
111 
112  ! regularization energy
113  penalty = penalty + pao%regularization*sum(v**2)
114  END IF
115 
116  IF (PRESENT(g)) THEN ! TURNING POINT (if calc grad) -------------------------
117 
118  cpassert(PRESENT(m1))
119 
120  ! calculate derivatives between eigenvectors of H
121  ALLOCATE (d1(n, n), m2(n, n), m3(n, n), m4(n, n))
122  DO i = 1, n
123  DO j = 1, n
124  ! ignore changes among occupied or virtual eigenvectors
125  ! They will get filtered out by M2*D1 anyways, however this early
126  ! intervention might stabilize numerics in the case of level-crossings.
127  IF (i <= m .EQV. j <= m) THEN
128  d1(i, j) = 0.0_dp
129  ELSE
130  denom = h_evals(i) - h_evals(j)
131  IF (abs(denom) > 1e-9_dp) THEN ! avoid division by zero
132  d1(i, j) = 1.0_dp/denom
133  ELSE
134  d1(i, j) = sign(1e+9_dp, denom)
135  END IF
136  END IF
137  END DO
138  END DO
139  IF (ASSOCIATED(m1)) THEN
140  m2 = matmul(transpose(m1), h_evecs)
141  ELSE
142  m2 = 0.0_dp
143  END IF
144  m3 = m2*d1 ! Hadamard product
145  m4 = matmul(matmul(h_evecs, m3), transpose(h_evecs))
146 
147  ! gradient contribution from penalty terms
148  IF (PRESENT(penalty)) THEN
149  ALLOCATE (d2(n, n))
150  d2 = 0.0_dp
151  DO i = 1, n
152  DO j = 1, n
153  IF (i <= m .EQV. j <= m) cycle
154  diff = h_evals(i) - h_evals(j)
155  d2(i, i) = d2(i, i) - 2.0_dp*alpha*diff/beta**2*exp(-(diff/beta)**2)
156  END DO
157  END DO
158  m4 = m4 + matmul(matmul(h_evecs, d2), transpose(h_evecs))
159  DEALLOCATE (d2)
160  END IF
161 
162  ! dH / dV, return to non-orthonormal basis
163  ALLOCATE (m5(n, n))
164  m5 = matmul(matmul(block_n, m4), block_n)
165 
166  ! add regularization gradient
167  IF (PRESENT(penalty)) &
168  m5 = m5 + 2.0_dp*pao%regularization*v
169 
170  ! symmetrize
171  g = 0.5_dp*(m5 + transpose(m5)) ! the final gradient
172 
173  DEALLOCATE (d1, m2, m3, m4, m5)
174  END IF
175 
176  DEALLOCATE (h, h_evals, h_evecs)
177 
178  CALL timestop(handle)
179  END SUBROUTINE pao_calc_u_block_fock
180 
181 END MODULE pao_param_fock
Defines the basic variable types.
Definition: kinds.F:23
integer, parameter, public dp
Definition: kinds.F:34
Collection of simple mathematical functions and subroutines.
Definition: mathlib.F:15
subroutine, public diamat_all(a, eigval, dac)
Diagonalize the symmetric n by n matrix a using the LAPACK library. Only the upper triangle of matrix...
Definition: mathlib.F:376
Common framework for using eigenvectors of a Fock matrix as PAO basis.
subroutine, public pao_calc_u_block_fock(pao, iatom, V, U, penalty, gap, evals, M1, G)
Calculate new matrix U and optinally its gradient G.
Types used by the PAO machinery.
Definition: pao_types.F:12