(git:e7e05ae)
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 ! **************************************************************************************************
22  cp_to_string
23  USE input_section_types, ONLY: section_vals_type,&
25  USE kinds, ONLY: default_string_length,&
26  dp
27  USE neb_types, ONLY: neb_type,&
28  neb_var_type
31  USE particle_types, ONLY: particle_type
32  USE replica_types, ONLY: replica_env_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 
46 CONTAINS
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 
372 END 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.
Definition: neb_opt_utils.F:20
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.
Definition: neb_opt_utils.F:64
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,...
Definition: replica_types.F:21