(git:374b731)
Loading...
Searching...
No Matches
neb_opt_utils.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 Module with utility to perform MD Nudged Elastic Band Calculation
10!> \note
11!> Numerical accuracy for parallel runs:
12!> Each replica starts the SCF run from the one optimized
13!> in a previous run. It may happen then energies and derivatives
14!> of a serial run and a parallel run could be slightly different
15!> 'cause of a different starting density matrix.
16!> Exact results are obtained using:
17!> EXTRAPOLATION USE_GUESS in QS section (Teo 09.2006)
18!> \author Teodoro Laino 10.2006
19! **************************************************************************************************
25 USE kinds, ONLY: default_string_length,&
26 dp
27 USE neb_types, ONLY: neb_type,&
33#include "../base/base_uses.f90"
34
35 IMPLICIT NONE
36 PRIVATE
37 CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'neb_opt_utils'
38 LOGICAL, PARAMETER, PRIVATE :: debug_this_module = .false.
39
40 PUBLIC :: accept_diis_step, &
41 neb_ls
42
43 REAL(KIND=dp), DIMENSION(2:10), PRIVATE :: acceptance_factor = &
44 (/0.97_dp, 0.84_dp, 0.71_dp, 0.67_dp, 0.62_dp, 0.56_dp, 0.49_dp, 0.41_dp, 0.0_dp/)
45
46CONTAINS
47
48! **************************************************************************************************
49!> \brief Performs few basic operations for the NEB DIIS optimization
50!> \param apply_diis ...
51!> \param n_diis ...
52!> \param err ...
53!> \param crr ...
54!> \param set_err ...
55!> \param sline ...
56!> \param coords ...
57!> \param check_diis ...
58!> \param iw2 ...
59!> \return ...
60!> \author Teodoro Laino 10.2006
61! **************************************************************************************************
62 FUNCTION accept_diis_step(apply_diis, n_diis, err, crr, set_err, sline, coords, &
63 check_diis, iw2) RESULT(accepted)
64 LOGICAL, INTENT(IN) :: apply_diis
65 INTEGER, INTENT(IN) :: n_diis
66 REAL(kind=dp), DIMENSION(:, :), POINTER :: err, crr
67 INTEGER, DIMENSION(:), POINTER :: set_err
68 TYPE(neb_var_type), POINTER :: sline, coords
69 LOGICAL, INTENT(IN) :: check_diis
70 INTEGER, INTENT(IN) :: iw2
71 LOGICAL :: accepted
72
73 CHARACTER(LEN=default_string_length) :: line
74 INTEGER :: i, iend, ind, indi, indj, info, istart, &
75 iv, iw, j, jv, k, lwork, np, nv
76 INTEGER, ALLOCATABLE, DIMENSION(:) :: iwork
77 LOGICAL :: increase_error
78 REAL(dp), DIMENSION(:, :), POINTER :: work
79 REAL(kind=dp) :: eps_svd
80 REAL(kind=dp), ALLOCATABLE, DIMENSION(:) :: s, work_dgesdd
81 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :) :: u, vt, wrk, wrk_inv
82 REAL(kind=dp), DIMENSION(:), POINTER :: awrk, cwrk, ref, step
83
85 accepted = .false.
86 ! find the index with the minimum element of the set_err array
87 nv = minloc(set_err, 1)
88 IF (iw2 > 0) WRITE (iw2, '(A,I3)') "Entering into the DIIS module. Error vector number:: ", nv
89 set_err(nv) = 1
90 eps_svd = 1.0e-10_dp
91 ALLOCATE (step(sline%size_wrk(1)*sline%size_wrk(2)))
92 ALLOCATE (ref(sline%size_wrk(1)*sline%size_wrk(2)))
93 err(:, nv) = reshape(sline%wrk, (/sline%size_wrk(1)*sline%size_wrk(2)/))
94 crr(:, nv) = reshape(coords%wrk, (/coords%size_wrk(1)*coords%size_wrk(2)/))
95 jv = n_diis
96 IF (all(set_err == 1) .AND. apply_diis) THEN
97 IF (iw2 > 0) WRITE (iw2, '(A)') "Applying DIIS equations"
98 ! Apply DIIS..
99 DO jv = 2, n_diis
100 np = jv + 1
101 IF (iw2 > 0) WRITE (iw2, '(A,I5,A)') "Applying DIIS equations with the last", &
102 jv, " error vectors"
103 ALLOCATE (wrk(np, np))
104 ALLOCATE (work(np, np))
105 ALLOCATE (wrk_inv(np, np))
106 ALLOCATE (cwrk(np))
107 ALLOCATE (awrk(np))
108 awrk = 0.0_dp
109 wrk = 1.0_dp
110 wrk(np, np) = 0.0_dp
111 awrk(np) = 1.0_dp
112 DO i = 1, jv
113 indi = n_diis - i + 1
114 DO j = i, jv
115 indj = n_diis - j + 1
116 wrk(i, j) = dot_product(err(:, indi), err(:, indj))
117 wrk(j, i) = wrk(i, j)
118 END DO
119 END DO
120 IF (iw2 > 0) THEN
121 line = "DIIS Matrix"//cp_to_string(np)//"x"//cp_to_string(np)//"."
122 WRITE (iw2, '(A)') trim(line)
123 WRITE (iw2, '('//cp_to_string(np)//'F12.6)') wrk
124 END IF
125 ! Inverte the DIIS Matrix
126 work = transpose(wrk)
127 ! Workspace query
128 ALLOCATE (iwork(8*np))
129 ALLOCATE (s(np))
130 ALLOCATE (u(np, np))
131 ALLOCATE (vt(np, np))
132 ALLOCATE (work_dgesdd(1))
133 lwork = -1
134 CALL dgesdd('S', np, np, work, np, s, u, np, vt, np, work_dgesdd, lwork, iwork, info)
135 lwork = int(work_dgesdd(1))
136 DEALLOCATE (work_dgesdd)
137 ALLOCATE (work_dgesdd(lwork))
138 CALL dgesdd('S', np, np, work, np, s, u, np, vt, np, work_dgesdd, lwork, iwork, info)
139 ! Construct the inverse
140 DO k = 1, np
141 ! Invert SV
142 IF (s(k) < eps_svd) THEN
143 s(k) = 0.0_dp
144 ELSE
145 s(k) = 1.0_dp/s(k)
146 END IF
147 vt(k, :) = vt(k, :)*s(k)
148 END DO
149 CALL dgemm('T', 'T', np, np, np, 1.0_dp, vt, np, u, np, 0.0_dp, wrk_inv, np)
150 DEALLOCATE (iwork)
151 DEALLOCATE (s)
152 DEALLOCATE (u)
153 DEALLOCATE (vt)
154 DEALLOCATE (work_dgesdd)
155 cwrk = matmul(wrk_inv, awrk)
156 ! Check the DIIS solution
157 step = 0.0_dp
158 ind = 0
159 DO i = n_diis, n_diis - jv + 1, -1
160 ind = ind + 1
161 step = step + (crr(:, i) + err(:, i))*cwrk(ind)
162 END DO
163 step = step - crr(:, n_diis)
164 ref = err(:, n_diis)
165 increase_error = check_diis_solution(jv, cwrk, step, ref, &
166 iw2, check_diis)
167 ! possibly enlarge the error space
168 IF (increase_error) THEN
169 accepted = .true.
170 sline%wrk = reshape(step, (/sline%size_wrk(1), sline%size_wrk(2)/))
171 ELSE
172 DEALLOCATE (awrk)
173 DEALLOCATE (cwrk)
174 DEALLOCATE (wrk)
175 DEALLOCATE (work)
176 DEALLOCATE (wrk_inv)
177 EXIT
178 END IF
179 DEALLOCATE (awrk)
180 DEALLOCATE (cwrk)
181 DEALLOCATE (wrk)
182 DEALLOCATE (work)
183 DEALLOCATE (wrk_inv)
184 END DO
185 IF (iw2 > 0) THEN
186 line = "Exiting DIIS accepting"//cp_to_string(min(n_diis, jv))//" errors."
187 WRITE (iw2, '(A)') trim(line)
188 END IF
189 END IF
190 IF (all(set_err == 1)) THEN
191 ! always delete the last error vector from the history vectors
192 ! move error vectors and the set_err in order to have free space
193 ! at the end of the err array
194 istart = max(2, n_diis - jv + 2)
195 iend = n_diis
196 indi = 0
197 DO iv = istart, iend
198 indi = indi + 1
199 err(:, indi) = err(:, iv)
200 crr(:, indi) = crr(:, iv)
201 set_err(indi) = 1
202 END DO
203 DO iv = indi + 1, iend
204 set_err(iv) = -1
205 END DO
206 END IF
207 DEALLOCATE (step)
208 DEALLOCATE (ref)
209
210 END FUNCTION accept_diis_step
211
212! **************************************************************************************************
213!> \brief Check conditions for the acceptance of the DIIS step
214!> \param nv ...
215!> \param cwrk ...
216!> \param step ...
217!> \param ref ...
218!> \param output_unit ...
219!> \param check_diis ...
220!> \return ...
221!> \author Teodoro Laino 10.2006
222! **************************************************************************************************
223 FUNCTION check_diis_solution(nv, cwrk, step, ref, output_unit, check_diis) &
224 result(accepted)
225 INTEGER, INTENT(IN) :: nv
226 REAL(kind=dp), DIMENSION(:), POINTER :: cwrk, step, ref
227 INTEGER, INTENT(IN) :: output_unit
228 LOGICAL, INTENT(IN) :: check_diis
229 LOGICAL :: accepted
230
231 REAL(kind=dp) :: costh, norm1, norm2
232 REAL(kind=dp), ALLOCATABLE, DIMENSION(:) :: tmp
233
234 accepted = .true.
235 ALLOCATE (tmp(SIZE(step)))
236 IF (accepted) THEN
237 ! (a) The direction of the DIIS step, can be compared to the reference step.
238 ! if the angle is grater than a specified value, the DIIS step is not
239 ! acceptable.
240 norm1 = sqrt(dot_product(ref, ref))
241 norm2 = sqrt(dot_product(step, step))
242 costh = dot_product(ref, step)/(norm1*norm2)
243 IF (check_diis) THEN
244 IF (costh < acceptance_factor(min(10, nv))) accepted = .false.
245 ELSE
246 IF (costh <= 0.0_dp) accepted = .false.
247 END IF
248 IF (output_unit > 0 .AND. (.NOT. accepted)) THEN
249 WRITE (output_unit, '(T2,"DIIS|",A)') &
250 "The direction of the DIIS step, can be compared to the reference step.", &
251 "If the angle is grater than a specified value, the DIIS step is not", &
252 "acceptable. Value exceeded. Reset DIIS!"
253 WRITE (output_unit, '(T2,"DIIS|",A,F6.3,A,F6.3,A)') &
254 "Present Cosine <", costh, "> compared with the optimal value <", &
255 acceptance_factor(min(10, nv)), "> ."
256 END IF
257 END IF
258 IF (accepted .AND. check_diis) THEN
259 ! (b) The length of the DIIS step is limited to be no more than 10 times
260 ! the reference step
261 IF (norm1 > norm2*10.0_dp) accepted = .false.
262 IF (output_unit > 0 .AND. (.NOT. accepted)) THEN
263 WRITE (output_unit, '(T2,"DIIS|",A)') &
264 "The length of the DIIS step is limited to be no more than 10 times", &
265 "the reference step. Value exceeded. Reset DIIS!"
266 END IF
267 END IF
268 IF (accepted .AND. check_diis) THEN
269 ! (d) If the DIIS matrix is nearly singular, the norm of the DIIS step
270 ! vector becomes small and cwrk/norm1 becomes large, signaling a
271 ! numerical stability problems. If the magnitude of cwrk/norm1
272 ! exceeds 10^8 then the step size is assumed to be unacceptable
273 IF (any(abs(cwrk(1:nv)/norm1) > 10**8_dp)) accepted = .false.
274 IF (output_unit > 0 .AND. (.NOT. accepted)) THEN
275 WRITE (output_unit, '(T2,"DIIS|",A)') &
276 "If the DIIS matrix is nearly singular, the norm of the DIIS step", &
277 "vector becomes small and Coeff/E_norm becomes large, signaling a", &
278 "numerical stability problems. IF the magnitude of Coeff/E_norm", &
279 "exceeds 10^8 THEN the step size is assumed to be unacceptable.", &
280 "Value exceeded. Reset DIIS!"
281 END IF
282 END IF
283 DEALLOCATE (tmp)
284 END FUNCTION check_diis_solution
285
286! **************************************************************************************************
287!> \brief Perform a line minimization search in optimizing a NEB with DIIS
288!> \param stepsize ...
289!> \param sline ...
290!> \param rep_env ...
291!> \param neb_env ...
292!> \param coords ...
293!> \param energies ...
294!> \param forces ...
295!> \param vels ...
296!> \param particle_set ...
297!> \param iw ...
298!> \param output_unit ...
299!> \param distances ...
300!> \param diis_section ...
301!> \param iw2 ...
302!> \author Teodoro Laino 10.2006
303! **************************************************************************************************
304 SUBROUTINE neb_ls(stepsize, sline, rep_env, neb_env, coords, energies, forces, &
305 vels, particle_set, iw, output_unit, distances, diis_section, iw2)
306 REAL(kind=dp), INTENT(INOUT) :: stepsize
307 TYPE(neb_var_type), POINTER :: sline
308 TYPE(replica_env_type), POINTER :: rep_env
309 TYPE(neb_type), OPTIONAL, POINTER :: neb_env
310 TYPE(neb_var_type), POINTER :: coords
311 REAL(kind=dp), DIMENSION(:), INTENT(INOUT) :: energies
312 TYPE(neb_var_type), POINTER :: forces, vels
313 TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
314 INTEGER, INTENT(IN) :: iw, output_unit
315 REAL(kind=dp), DIMENSION(:), INTENT(INOUT) :: distances
316 TYPE(section_vals_type), POINTER :: diis_section
317 INTEGER, INTENT(IN) :: iw2
318
319 INTEGER :: i, np
320 REAL(kind=dp) :: a, b, max_stepsize, xa, xb, xc_cray, ya, &
321 yb
322 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :) :: icoord
323
324! replaced xc by xc_cray to work around yet another bug in pgf90 on CRAY xt3
325
326 ALLOCATE (icoord(coords%size_wrk(1), coords%size_wrk(2)))
327 CALL section_vals_val_get(diis_section, "NP_LS", i_val=np)
328 CALL section_vals_val_get(diis_section, "MAX_STEPSIZE", r_val=max_stepsize)
329 icoord(:, :) = coords%wrk
330 xa = 0.0_dp
331 ya = sum(sline%wrk*forces%wrk)
332 xb = xa + min(ya*stepsize, max_stepsize)
333 xc_cray = xb
334 i = 1
335 DO WHILE (i <= np - 1)
336 i = i + 1
337 coords%wrk = icoord + xb*sline%wrk
338 CALL reorient_images(neb_env%rotate_frames, particle_set, coords, vels, &
339 output_unit, distances, neb_env%number_of_replica)
340 neb_env%avg_distance = sqrt(sum(distances*distances)/real(SIZE(distances), kind=dp))
341 CALL neb_calc_energy_forces(rep_env, neb_env, coords, energies, forces, &
342 particle_set, iw)
343 yb = sum(sline%wrk*forces%wrk)
344 a = (ya - yb)/(2.0_dp*(xa - xb))
345 b = ya - 2.0_dp*a*xa
346 xc_cray = -b/(2.0_dp*a)
347 IF (xc_cray > max_stepsize) THEN
348 IF (iw2 > 0) WRITE (iw2, '(T2,2(A,F6.3),A)') &
349 "LS| Predicted stepsize (", xc_cray, ") greater than allowed stepsize (", &
350 max_stepsize, "). Reset!"
351 xc_cray = max_stepsize
352 EXIT
353 END IF
354 ! No Extrapolation .. only interpolation
355 IF ((xc_cray <= min(xa, xb) .OR. xc_cray >= max(xa, xb)) .AND. (abs(xa - xb) > 1.0e-5_dp)) THEN
356 IF (iw2 > 0) WRITE (iw2, '(T2,2(A,I5),A)') &
357 "LS| Increasing the number of point from ", np, " to ", np + 1, "."
358 np = np + 1
359 END IF
360 !
361 IF (abs(yb) < abs(ya)) THEN
362 ya = yb
363 xa = xb
364 END IF
365 xb = xc_cray
366 END DO
367 stepsize = xc_cray
368 coords%wrk = icoord
369 DEALLOCATE (icoord)
370 END SUBROUTINE neb_ls
371
372END MODULE neb_opt_utils
static void dgemm(const char transa, const char transb, const int m, const int n, const int k, const double alpha, const double *a, const int lda, const double *b, const int ldb, const double beta, double *c, const int ldc)
Convenient wrapper to hide Fortran nature of dgemm_, swapping a and b.
various routines to log and control the output. The idea is that decisions about where to log should ...
integer function, public cp_logger_get_default_io_unit(logger)
returns the unit nr for the ionode (-1 on all other processors) skips as well checks if the procs cal...
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
integer, parameter, public default_string_length
Definition kinds.F:57
Module with utility to perform MD Nudged Elastic Band Calculation.
logical function, public accept_diis_step(apply_diis, n_diis, err, crr, set_err, sline, coords, check_diis, iw2)
Performs few basic operations for the NEB DIIS optimization.
subroutine, public neb_ls(stepsize, sline, rep_env, neb_env, coords, energies, forces, vels, particle_set, iw, output_unit, distances, diis_section, iw2)
Perform a line minimization search in optimizing a NEB with DIIS.
Typo for Nudged Elastic Band Calculation.
Definition neb_types.F:20
Module with utility for Nudged Elastic Band Calculation.
Definition neb_utils.F:20
subroutine, public neb_calc_energy_forces(rep_env, neb_env, coords, energies, forces, particle_set, output_unit)
Driver to compute energy and forces within a NEB, Based on the use of the replica_env.
Definition neb_utils.F:367
subroutine, public reorient_images(rotate_frames, particle_set, coords, vels, iw, distances, number_of_replica)
Reorient iteratively all images of the NEB chain in order to have always the smaller RMSD between two...
Definition neb_utils.F:877
Define the data structure for the particle information.
types used to handle many replica of the same system that differ only in atom positions,...
keeps replicated information about the replicas