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 Optimizer for the atomic code
10 : ! **************************************************************************************************
11 : MODULE atom_optimization
12 : USE atom_types, ONLY: atom_optimization_type
13 : USE kinds, ONLY: dp
14 : USE lapack, ONLY: lapack_sgelss
15 : #include "./base/base_uses.f90"
16 :
17 : IMPLICIT NONE
18 :
19 : PRIVATE
20 :
21 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'atom_optimization'
22 :
23 : TYPE hmat_type
24 : REAL(dp) :: energy = 0.0_dp
25 : REAL(dp) :: error = 0.0_dp
26 : REAL(dp), DIMENSION(:, :, :), POINTER :: emat => NULL()
27 : REAL(dp), DIMENSION(:, :, :), POINTER :: fmat => NULL()
28 : REAL(dp), DIMENSION(:, :, :), POINTER :: pmat => NULL()
29 : END TYPE hmat_type
30 :
31 : TYPE atom_history_type
32 : INTEGER :: max_history = 0
33 : INTEGER :: hlen = 0
34 : INTEGER :: hpos = 0
35 : REAL(dp) :: damping = 0.0_dp
36 : REAL(dp) :: eps_diis = 0.0_dp
37 : REAL(dp), DIMENSION(:, :), POINTER :: dmat => NULL()
38 : TYPE(hmat_type), DIMENSION(:), POINTER :: hmat => NULL()
39 : END TYPE atom_history_type
40 :
41 : PUBLIC :: atom_opt_fmat, &
42 : atom_history_type, atom_history_init, atom_history_update, atom_history_release
43 :
44 : CONTAINS
45 :
46 : ! **************************************************************************************************
47 : !> \brief Initialise a circular buffer to keep Kohn-Sham and density matrices from previous iteration.
48 : !> \param history object to initialise
49 : !> \param optimization optimisation parameters
50 : !> \param matrix reference matrix. Historic matrices will have the same size as
51 : !> this reference matrix
52 : !> \par History
53 : !> * 08.2016 new structure element: density matrix [Juerg Hutter]
54 : !> * 08.2008 created [Juerg Hutter]
55 : ! **************************************************************************************************
56 11277 : PURE SUBROUTINE atom_history_init(history, optimization, matrix)
57 : TYPE(atom_history_type), INTENT(INOUT) :: history
58 : TYPE(atom_optimization_type), INTENT(IN) :: optimization
59 : REAL(dp), DIMENSION(:, :, :), INTENT(IN) :: matrix
60 :
61 : INTEGER :: i, n1, n2, n3, ndiis
62 : REAL(dp) :: damp, eps
63 :
64 11277 : ndiis = optimization%n_diis
65 11277 : eps = optimization%eps_diis
66 11277 : damp = optimization%damping
67 :
68 11277 : CALL atom_history_release(history)
69 :
70 11277 : history%max_history = ndiis
71 11277 : history%hlen = 0
72 11277 : history%hpos = 0
73 11277 : history%damping = damp
74 11277 : history%eps_diis = eps
75 45108 : ALLOCATE (history%dmat(ndiis + 1, ndiis + 1))
76 :
77 90218 : ALLOCATE (history%hmat(ndiis))
78 11277 : n1 = SIZE(matrix, 1)
79 11277 : n2 = SIZE(matrix, 2)
80 11277 : n3 = SIZE(matrix, 3)
81 67664 : DO i = 1, ndiis
82 56387 : history%hmat(i)%energy = 0.0_dp
83 56387 : history%hmat(i)%error = 0.0_dp
84 281895 : ALLOCATE (history%hmat(i)%emat(n1, n2, n3))
85 225508 : ALLOCATE (history%hmat(i)%fmat(n1, n2, n3))
86 236785 : ALLOCATE (history%hmat(i)%pmat(n1, n2, n3))
87 : END DO
88 :
89 11277 : END SUBROUTINE atom_history_init
90 :
91 : ! **************************************************************************************************
92 : !> \brief Add matrices from the current iteration into the circular buffer.
93 : !> \param history object to keep historic matrices
94 : !> \param pmat density matrix
95 : !> \param fmat Kohn-Sham matrix
96 : !> \param emat error matrix
97 : !> \param energy total energy
98 : !> \param error convergence
99 : !> \par History
100 : !> * 08.2016 new formal argument: density matrix [Juerg Hutter]
101 : !> * 08.2008 created [Juerg Hutter]
102 : ! **************************************************************************************************
103 66460 : PURE SUBROUTINE atom_history_update(history, pmat, fmat, emat, energy, error)
104 : TYPE(atom_history_type), INTENT(INOUT) :: history
105 : REAL(dp), DIMENSION(:, :, :), INTENT(IN) :: pmat, fmat, emat
106 : REAL(dp), INTENT(IN) :: energy, error
107 :
108 : INTEGER :: nlen, nmax, nnow
109 :
110 66460 : nmax = history%max_history
111 66460 : nlen = MIN(history%hlen + 1, nmax)
112 66460 : nnow = history%hpos + 1
113 66460 : IF (nnow > nmax) nnow = 1
114 :
115 66460 : history%hmat(nnow)%energy = energy
116 66460 : history%hmat(nnow)%error = error
117 34202008 : history%hmat(nnow)%pmat = pmat
118 34202008 : history%hmat(nnow)%fmat = fmat
119 34202008 : history%hmat(nnow)%emat = emat
120 :
121 66460 : history%hlen = nlen
122 66460 : history%hpos = nnow
123 :
124 66460 : END SUBROUTINE atom_history_update
125 :
126 : ! **************************************************************************************************
127 : !> \brief Release circular buffer to keep historic matrices.
128 : !> \param history object to release
129 : !> \par History
130 : !> * 08.2008 created [Juerg Hutter]
131 : ! **************************************************************************************************
132 22554 : PURE SUBROUTINE atom_history_release(history)
133 : TYPE(atom_history_type), INTENT(INOUT) :: history
134 :
135 : INTEGER :: i
136 :
137 22554 : history%max_history = 0
138 22554 : history%hlen = 0
139 22554 : history%hpos = 0
140 22554 : history%damping = 0._dp
141 22554 : history%eps_diis = 0._dp
142 22554 : IF (ASSOCIATED(history%dmat)) THEN
143 11277 : DEALLOCATE (history%dmat)
144 : END IF
145 22554 : IF (ASSOCIATED(history%hmat)) THEN
146 67664 : DO i = 1, SIZE(history%hmat)
147 56387 : IF (ASSOCIATED(history%hmat(i)%emat)) THEN
148 56387 : DEALLOCATE (history%hmat(i)%emat)
149 : END IF
150 56387 : IF (ASSOCIATED(history%hmat(i)%fmat)) THEN
151 56387 : DEALLOCATE (history%hmat(i)%fmat)
152 : END IF
153 67664 : IF (ASSOCIATED(history%hmat(i)%pmat)) THEN
154 56387 : DEALLOCATE (history%hmat(i)%pmat)
155 : END IF
156 : END DO
157 11277 : DEALLOCATE (history%hmat)
158 : END IF
159 :
160 22554 : END SUBROUTINE atom_history_release
161 :
162 : ! **************************************************************************************************
163 : !> \brief Construct a Kohn-Sham matrix for the next iteration based on the historic data.
164 : !> \param fmat new Kohn-Sham matrix
165 : !> \param history historic matrices
166 : !> \param err convergence
167 : !> \par History
168 : !> * 08.2016 renamed to atom_opt_fmat() [Juerg Hutter]
169 : !> * 08.2008 created as atom_opt() [Juerg Hutter]
170 : ! **************************************************************************************************
171 66460 : SUBROUTINE atom_opt_fmat(fmat, history, err)
172 : REAL(dp), DIMENSION(:, :, :), INTENT(INOUT) :: fmat
173 : TYPE(atom_history_type), INTENT(INOUT) :: history
174 : REAL(dp), INTENT(IN) :: err
175 :
176 : INTEGER :: i, info, j, lwork, na, nb, nlen, nm, &
177 : nmax, nnow, rank
178 : REAL(dp) :: a, rcond, t
179 66460 : REAL(dp), ALLOCATABLE, DIMENSION(:) :: s, work
180 66460 : REAL(dp), ALLOCATABLE, DIMENSION(:, :) :: vec
181 :
182 66460 : nmax = history%max_history
183 66460 : nnow = history%hpos
184 66460 : a = history%damping
185 66460 : IF (history%hlen > 1) THEN
186 57303 : IF (err < history%eps_diis) THEN
187 : ! DIIS
188 57303 : rcond = 1.e-10_dp
189 57303 : lwork = 25*nmax
190 458424 : ALLOCATE (vec(nmax + 1, 2), s(nmax + 1), work(lwork))
191 : nlen = history%hlen
192 859569 : vec = 0._dp
193 57303 : vec(nlen + 1, 1) = 1._dp
194 297606 : history%dmat(1:nlen, nlen + 1) = 1._dp
195 297606 : history%dmat(nlen + 1, 1:nlen) = 1._dp
196 57303 : history%dmat(nlen + 1, nlen + 1) = 0._dp
197 297606 : DO i = 1, nlen
198 240303 : na = nnow + 1 - i
199 240303 : IF (na < 1) na = nmax + na
200 960138 : DO j = i, nlen
201 662532 : nb = nnow + 1 - j
202 662532 : IF (nb < 1) nb = nmax + nb
203 373658244 : t = SUM(history%hmat(na)%emat*history%hmat(nb)%emat)
204 662532 : history%dmat(i, j) = t
205 902835 : history%dmat(j, i) = t
206 : END DO
207 : END DO
208 : CALL lapack_sgelss(nlen + 1, nlen + 1, 1, history%dmat, nmax + 1, vec, nmax + 1, s, &
209 57303 : rcond, rank, work, lwork, info)
210 57303 : CPASSERT(info == 0)
211 30751281 : fmat = 0._dp
212 297606 : DO i = 1, nlen
213 240303 : na = nnow + 1 - i
214 240303 : IF (na < 1) na = nmax + na
215 133552716 : fmat = fmat + vec(i, 1)*history%hmat(na)%fmat
216 : END DO
217 :
218 57303 : DEALLOCATE (vec, s, work)
219 : ELSE
220 : ! damping
221 0 : nm = nnow - 1
222 0 : IF (nm < 1) nm = history%max_history
223 0 : fmat = a*history%hmat(nnow)%fmat + (1._dp - a)*history%hmat(nm)%fmat
224 : END IF
225 9157 : ELSEIF (history%hlen == 1) THEN
226 3450727 : fmat = history%hmat(nnow)%fmat
227 : ELSE
228 0 : CPABORT("")
229 : END IF
230 :
231 66460 : END SUBROUTINE atom_opt_fmat
232 :
233 0 : END MODULE atom_optimization
|