(git:21ef868)
Loading...
Searching...
No Matches
glbopt_history.F
Go to the documentation of this file.
1!--------------------------------------------------------------------------------------------------!
2! CP2K: A general program to perform molecular dynamics simulations !
3! Copyright 2000-2026 CP2K developers group <https://cp2k.org> !
4! !
5! SPDX-License-Identifier: GPL-2.0-or-later !
6!--------------------------------------------------------------------------------------------------!
7
8! **************************************************************************************************
9!> \brief History of minima, calculates, stores and compares fingerprints of minima.
10!> Used by Minima Hopping and Minima Crawling.
11!> \author Ole Schuett
12! **************************************************************************************************
16 USE kinds, ONLY: dp
17#include "../base/base_uses.f90"
18
19 IMPLICIT NONE
20 PRIVATE
21
23 PRIVATE
24 REAL(KIND=dp) :: epot = 0.0
25 REAL(kind=dp), DIMENSION(:), ALLOCATABLE :: goedecker
27
28 TYPE history_entry_type
29 TYPE(history_fingerprint_type), POINTER :: p => null()
30 INTEGER :: id = -1
31 END TYPE history_entry_type
32
34 PRIVATE
35 TYPE(history_entry_type), DIMENSION(:), POINTER :: entries => null()
36 INTEGER :: length = 0
37 INTEGER :: iw = -1
38 REAL(kind=dp) :: e_precision = 0.0
39 REAL(kind=dp) :: fp_precision = 0.0
40 END TYPE history_type
41
45 PUBLIC :: history_fingerprint
47
48 LOGICAL, PARAMETER :: debug = .false.
49 INTEGER, PARAMETER :: history_grow_unit = 1000
50CONTAINS
51
52! **************************************************************************************************
53!> \brief Initializes a history.
54!> \param history ...
55!> \param history_section ...
56!> \param iw ...
57!> \author Ole Schuett
58! **************************************************************************************************
59 SUBROUTINE history_init(history, history_section, iw)
60 TYPE(history_type), INTENT(INOUT) :: history
61 TYPE(section_vals_type), POINTER :: history_section
62 INTEGER :: iw
63
64 ALLOCATE (history%entries(history_grow_unit))
65 history%iw = iw
66 CALL section_vals_val_get(history_section, "ENERGY_PRECISION", &
67 r_val=history%E_precision)
68 CALL section_vals_val_get(history_section, "FINGERPRINT_PRECISION", &
69 r_val=history%FP_precision)
70
71 IF (iw > 0) THEN
72 WRITE (iw, '(A,T66,E15.3)') &
73 " GLBOPT| History energy precision", history%E_precision
74 WRITE (iw, '(A,T66,E15.3)') &
75 " GLBOPT| History fingerprint precision", history%FP_precision
76 END IF
77 END SUBROUTINE history_init
78
79! **************************************************************************************************
80!> \brief Calculates a fingerprint for a given configuration.
81!> \param Epot ...
82!> \param pos ...
83!> \return ...
84!> \author Ole Schuett
85! **************************************************************************************************
86 FUNCTION history_fingerprint(Epot, pos) RESULT(fp)
87 REAL(kind=dp), INTENT(IN) :: epot
88 REAL(kind=dp), DIMENSION(:), INTENT(IN) :: pos
89 TYPE(history_fingerprint_type) :: fp
90
91 INTEGER :: handle
92 REAL(kind=dp), DIMENSION(:), POINTER :: tmp
93
94 CALL timeset("glbopt_history_fingerprint", handle)
95
96 NULLIFY (tmp)
97 fp%Epot = epot
98 CALL goedecker_fingerprint(pos, tmp)
99
100 !copy pointer to allocatable
101 ALLOCATE (fp%goedecker(SIZE(tmp)))
102 fp%goedecker(:) = tmp
103 DEALLOCATE (tmp)
104
105 CALL timestop(handle)
106 END FUNCTION history_fingerprint
107
108! **************************************************************************************************
109!> \brief Helper routine for history_fingerprint.
110!> Calculates a fingerprint based on inter-atomic distances.
111!> \param pos ...
112!> \param res ...
113!> \author Stefan Goedecker
114! **************************************************************************************************
115 SUBROUTINE goedecker_fingerprint(pos, res)
116 REAL(kind=dp), DIMENSION(:), INTENT(IN) :: pos
117 REAL(kind=dp), DIMENSION(:), POINTER :: res
118
119 INTEGER :: i, info, j, n
120 REAL(kind=dp) :: d2, t
121 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :) :: matrix, work
122 REAL(kind=dp), DIMENSION(3) :: d
123
124 IF (ASSOCIATED(res)) cpabort("goedecker_fingerprint: res already allocated")
125 n = SIZE(pos)/3 ! number of atoms
126
127 ALLOCATE (matrix(n, n), work(n, n))
128 DO i = 1, n
129 matrix(i, i) = 1.0
130 DO j = i + 1, n
131 d = pos(3*i - 2:3*i) - pos(3*j - 2:3*j)
132 d2 = sum(d**2)
133 t = exp(-0.5*d2)
134 matrix(i, j) = t
135 matrix(j, i) = t
136 END DO
137 END DO
138 ALLOCATE (res(n))
139 ! matrix values are garbage on exit because of jobz='N'
140 CALL dsyev('N', 'U', n, matrix, n, res, work, n**2, info)
141 IF (info /= 0) cpabort("goedecker_fingerprint: DSYEV failed")
142 END SUBROUTINE goedecker_fingerprint
143
144! **************************************************************************************************
145!> \brief Checks if two given fingerprints match.
146!> \param history ...
147!> \param fp1 ...
148!> \param fp2 ...
149!> \return ...
150!> \author Ole Schuett
151! **************************************************************************************************
152 FUNCTION history_fingerprint_match(history, fp1, fp2) RESULT(res)
153 TYPE(history_type), INTENT(IN) :: history
154 TYPE(history_fingerprint_type), INTENT(IN) :: fp1, fp2
155 LOGICAL :: res
156
157 res = (abs(fp1%Epot - fp2%Epot) < history%E_precision) .AND. &
158 (fingerprint_distance(fp1, fp2) < history%fp_precision)
159
160 END FUNCTION history_fingerprint_match
161
162! **************************************************************************************************
163!> \brief Helper routine for history_fingerprint_match
164!> Calculates the distance between two given fingerprints.
165!> \param fp1 ...
166!> \param fp2 ...
167!> \return ...
168!> \author Stefan Goedecker
169! **************************************************************************************************
170 PURE FUNCTION fingerprint_distance(fp1, fp2) RESULT(res)
171 TYPE(history_fingerprint_type), INTENT(IN) :: fp1, fp2
172 REAL(kind=dp) :: res
173
174 res = sqrt(sum((fp1%goedecker - fp2%goedecker)**2)/SIZE(fp1%goedecker))
175 END FUNCTION fingerprint_distance
176
177! **************************************************************************************************
178!> \brief Addes a new fingerprints to the history.
179!> Optionally, an abitrary id can be stored alongside the fingerprint.
180!> \param history ...
181!> \param fingerprint ...
182!> \param id ...
183!> \author Ole Schuett
184! **************************************************************************************************
185 SUBROUTINE history_add(history, fingerprint, id)
186 TYPE(history_type), INTENT(INOUT) :: history
187 TYPE(history_fingerprint_type), INTENT(IN) :: fingerprint
188 INTEGER, INTENT(IN), OPTIONAL :: id
189
190 INTEGER :: handle, i, k, n
191 TYPE(history_entry_type), DIMENSION(:), POINTER :: tmp
192
193 CALL timeset("glbopt_history_add", handle)
194
195 n = SIZE(history%entries)
196 IF (n == history%length) THEN
197 ! grow history%entries array
198 tmp => history%entries
199 ALLOCATE (history%entries(n + history_grow_unit))
200 history%entries(1:n) = tmp(:)
201 DEALLOCATE (tmp)
202 n = n + history_grow_unit
203 END IF
204
205 k = interpolation_search(history, fingerprint%Epot)
206
207 !history%entries(k+1:) = history%entries(k:n-1)
208 !Workaround for an XLF bug - pointer array copy does
209 !not work correctly
210 DO i = n, k + 1, -1
211 history%entries(i) = history%entries(i - 1)
212 END DO
213
214 ALLOCATE (history%entries(k)%p)
215 history%entries(k)%p = fingerprint
216 IF (PRESENT(id)) THEN
217 history%entries(k)%id = id
218 END IF
219 history%length = history%length + 1
220
221 IF (debug) THEN
222 ! check history for correct order
223 DO k = 1, history%length
224 !WRITE(*,*) "history: ", k, "Epot",history%entries(k)%p%Epot
225 IF (k > 1) THEN
226 IF (history%entries(k - 1)%p%Epot > history%entries(k)%p%Epot) THEN
227 cpabort("history_add: history in wrong order")
228 END IF
229 END IF
230 END DO
231 END IF
232
233 CALL timestop(handle)
234 END SUBROUTINE history_add
235
236! **************************************************************************************************
237!> \brief Checks if a given fingerprints is contained in the history.
238!> \param history ...
239!> \param fingerprint ...
240!> \param found ...
241!> \param id ...
242!> \author Ole Schuett
243! **************************************************************************************************
244 SUBROUTINE history_lookup(history, fingerprint, found, id)
245 TYPE(history_type), INTENT(IN) :: history
246 TYPE(history_fingerprint_type), INTENT(IN) :: fingerprint
247 LOGICAL, INTENT(OUT) :: found
248 INTEGER, INTENT(OUT), OPTIONAL :: id
249
250 INTEGER :: found_i, handle, i, k, k_max, k_min
251 REAL(kind=dp) :: best_match, dist, epot
252
253 CALL timeset("glbopt_history_lookup", handle)
254
255 found = .false.
256 IF (PRESENT(id)) id = -1
257 best_match = huge(1.0_dp)
258
259 IF (history%length > 0) THEN
260 epot = fingerprint%Epot
261 k = interpolation_search(history, fingerprint%Epot)
262
263 DO k_min = k - 1, 1, -1
264 IF (history%entries(k_min)%p%Epot < epot - history%E_precision) EXIT
265 END DO
266
267 DO k_max = k, history%length
268 IF (history%entries(k_max)%p%Epot > epot + history%E_precision) EXIT
269 END DO
270
271 k_min = max(k_min + 1, 1)
272 k_max = min(k_max - 1, history%length)
273
274 IF (debug) found_i = -1
275
276 DO i = k_min, k_max
277 dist = fingerprint_distance(fingerprint, history%entries(i)%p)
278 !WRITE(*,*) "entry ", i, " dist: ",dist
279 IF (dist < history%fp_precision .AND. dist < best_match) THEN
280 best_match = dist
281 found = .true.
282 IF (PRESENT(id)) id = history%entries(i)%id
283 IF (debug) found_i = i
284 END IF
285 END DO
286
287 IF (debug) CALL verify_history_lookup(history, fingerprint, found_i)
288 END IF
289
290 CALL timestop(handle)
291
292 END SUBROUTINE history_lookup
293
294! **************************************************************************************************
295!> \brief Helper routine for history_lookup
296!> \param history ...
297!> \param Efind ...
298!> \return ...
299!> \author Ole Schuett
300! **************************************************************************************************
301 FUNCTION interpolation_search(history, Efind) RESULT(res)
302 TYPE(history_type), INTENT(IN) :: history
303 REAL(kind=dp), INTENT(IN) :: efind
304 INTEGER :: res
305
306 INTEGER :: high, low, mid
307 REAL(kind=dp) :: slope
308
309 low = 1
310 high = history%length
311
312 DO WHILE (low < high)
313 !linear interpolation
314 slope = real(high - low, kind=dp)/(history%entries(high)%p%Epot - history%entries(low)%p%Epot)
315 mid = low + int(slope*(efind - history%entries(low)%p%Epot))
316 mid = min(max(mid, low), high)
317
318 IF (history%entries(mid)%p%Epot < efind) THEN
319 low = mid + 1
320 ELSE
321 high = mid - 1
322 END IF
323 END DO
324
325 IF (0 < low .AND. low <= history%length) THEN
326 IF (efind > history%entries(low)%p%Epot) low = low + 1
327 END IF
328
329 res = low
330 END FUNCTION interpolation_search
331
332! **************************************************************************************************
333!> \brief Debugging routine, performs a slow (but robust) linear search.
334!> \param history ...
335!> \param fingerprint ...
336!> \param found_i_ref ...
337!> \author Ole Schuett
338! **************************************************************************************************
339 SUBROUTINE verify_history_lookup(history, fingerprint, found_i_ref)
340 TYPE(history_type), INTENT(IN) :: history
341 TYPE(history_fingerprint_type), INTENT(IN) :: fingerprint
342 INTEGER, INTENT(IN) :: found_i_ref
343
344 INTEGER :: found_i, i
345 REAL(kind=dp) :: best_fp_match, epot_dist, fp_dist
346
347 found_i = -1
348 best_fp_match = huge(1.0_dp)
349
350 DO i = 1, history%length
351 epot_dist = abs(fingerprint%Epot - history%entries(i)%p%Epot)
352 IF (epot_dist > history%E_precision) cycle
353 fp_dist = fingerprint_distance(fingerprint, history%entries(i)%p)
354 !WRITE(*,*) "entry ", i, " dist: ",dist
355 IF (fp_dist < history%fp_precision .AND. fp_dist < best_fp_match) THEN
356 best_fp_match = fp_dist
357 found_i = i
358 END IF
359 END DO
360
361 IF (found_i /= found_i_ref) THEN
362 WRITE (*, *) found_i, found_i_ref
363 cpabort("verify_history_lookup failed")
364 END IF
365
366 END SUBROUTINE verify_history_lookup
367
368! **************************************************************************************************
369!> \brief Finalizes a history.
370!> \param history ...
371!> \author Ole Schuett
372! **************************************************************************************************
373 SUBROUTINE history_finalize(history)
374 TYPE(history_type) :: history
375
376 INTEGER :: i
377
378 DO i = 1, history%length
379 IF (ASSOCIATED(history%entries(i)%p)) THEN
380 DEALLOCATE (history%entries(i)%p)
381 END IF
382 END DO
383
384 DEALLOCATE (history%entries)
385
386 END SUBROUTINE history_finalize
387
388END MODULE glbopt_history
History of minima, calculates, stores and compares fingerprints of minima. Used by Minima Hopping and...
subroutine, public history_init(history, history_section, iw)
Initializes a history.
type(history_fingerprint_type) function, public history_fingerprint(epot, pos)
Calculates a fingerprint for a given configuration.
subroutine, public history_lookup(history, fingerprint, found, id)
Checks if a given fingerprints is contained in the history.
logical, parameter debug
subroutine, public history_finalize(history)
Finalizes a history.
subroutine, public history_add(history, fingerprint, id)
Addes a new fingerprints to the history. Optionally, an abitrary id can be stored alongside the finge...
logical function, public history_fingerprint_match(history, fp1, fp2)
Checks if two given fingerprints match.
objects that represent the structure of input sections and the data contained in an input section
subroutine, public section_vals_val_get(section_vals, keyword_name, i_rep_section, i_rep_val, n_rep_val, val, l_val, i_val, r_val, c_val, l_vals, i_vals, r_vals, c_vals, explicit)
returns the requested value
Defines the basic variable types.
Definition kinds.F:23
integer, parameter, public dp
Definition kinds.F:34