Line data Source code
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 Control parameters for optimizers that work with CDFT constraints
10 : !> \par History
11 : !> separated from scf_control_types [03.2018]
12 : !> \author Nico Holmberg [03.2018]
13 : ! **************************************************************************************************
14 : MODULE qs_cdft_opt_types
15 :
16 : USE input_constants, ONLY: &
17 : broyden_type_1, broyden_type_1_explicit, broyden_type_1_explicit_ls, broyden_type_1_ls, &
18 : broyden_type_2, broyden_type_2_explicit, broyden_type_2_explicit_ls, broyden_type_2_ls, &
19 : outer_scf_optimizer_broyden, outer_scf_optimizer_newton, outer_scf_optimizer_newton_ls
20 : USE input_section_types, ONLY: section_vals_get_subs_vals,&
21 : section_vals_type,&
22 : section_vals_val_get
23 : USE kinds, ONLY: dp
24 : #include "./base/base_uses.f90"
25 :
26 : IMPLICIT NONE
27 :
28 : PRIVATE
29 :
30 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_cdft_opt_types'
31 :
32 : ! Public data types
33 :
34 : PUBLIC :: cdft_opt_type
35 :
36 : ! Public subroutines
37 :
38 : PUBLIC :: cdft_opt_type_create, &
39 : cdft_opt_type_release, &
40 : cdft_opt_type_read, &
41 : cdft_opt_type_write, &
42 : cdft_opt_type_copy
43 :
44 : ! **************************************************************************************************
45 : !> \brief contains the parameters needed by CDFT specific optimizers
46 : !> \param build_jacobian logical which determines if the inverse Jacobian should be computed
47 : !> \param jacobian_step the step size for calculating the finite difference Jacobian
48 : !> \param newton_step the step size used by the Newton optimizer with values between 0 and 1
49 : !> \param newton_step_save permanent copy of the above
50 : !> \param jacobian_type the finite difference scheme to compute the Jacobian
51 : !> \param broyden_type the variant of Broyden's method to use
52 : !> \param jacobian_freq control parameters defining how often the Jacobian is built
53 : !> \param ijacobian counter to track how many SCF iterations/energy evaluations have passed since
54 : !> the last Jacobian rebuild
55 : !> \param broyden_update logical which determines if a Broyden update is needed
56 : !> \param max_ls the maximum number of backtracking line search steps to perform
57 : !> \param continue_ls continue line search until max steps are reached or until the gradient
58 : !> no longer decreases
59 : !> \param factor_ls line search parameter used in generating a new step size
60 : !> \par History
61 : !> created [03.2018]
62 : !> \author Nico Holmberg [03.2018]
63 : ! **************************************************************************************************
64 :
65 : TYPE cdft_opt_type
66 : LOGICAL :: build_jacobian = .FALSE.
67 : LOGICAL :: broyden_update = .FALSE.
68 : LOGICAL :: continue_ls = .FALSE.
69 : LOGICAL :: jacobian_restart = .FALSE.
70 : REAL(KIND=dp) :: newton_step = 0.0_dp
71 : REAL(KIND=dp) :: newton_step_save = 0.0_dp
72 : REAL(KIND=dp) :: factor_ls = 0.0_dp
73 : REAL(KIND=dp), DIMENSION(:), &
74 : ALLOCATABLE :: jacobian_step
75 : REAL(KIND=dp), DIMENSION(:), &
76 : POINTER :: jacobian_vector => NULL()
77 : INTEGER :: jacobian_type = -1
78 : INTEGER :: broyden_type = -1
79 : INTEGER :: jacobian_freq(2) = -1
80 : INTEGER :: ijacobian(2) = -1
81 : INTEGER :: max_ls = -1
82 : END TYPE cdft_opt_type
83 :
84 : CONTAINS
85 :
86 : ! **************************************************************************************************
87 : !> \brief allocates and initializes the CDFT optimizer control object with default values
88 : !> \param cdft_opt_control the object to initialize
89 : !> \par History
90 : !> 03.2018 created [Nico Holmberg]
91 : !> \author Nico Holmberg
92 : ! **************************************************************************************************
93 484 : SUBROUTINE cdft_opt_type_create(cdft_opt_control)
94 :
95 : TYPE(cdft_opt_type), POINTER :: cdft_opt_control
96 :
97 : CHARACTER(LEN=*), PARAMETER :: routineN = 'cdft_opt_type_create'
98 :
99 : INTEGER :: handle
100 :
101 484 : CALL timeset(routineN, handle)
102 :
103 484 : CPASSERT(.NOT. ASSOCIATED(cdft_opt_control))
104 3388 : ALLOCATE (cdft_opt_control)
105 :
106 : ! Load the default values
107 :
108 : cdft_opt_control%jacobian_type = -1
109 : cdft_opt_control%broyden_type = -1
110 1452 : cdft_opt_control%jacobian_freq(:) = 1
111 484 : cdft_opt_control%newton_step = 1.0_dp
112 484 : cdft_opt_control%newton_step_save = 1.0_dp
113 484 : cdft_opt_control%factor_ls = 0.5_dp
114 1452 : cdft_opt_control%ijacobian(:) = 0
115 484 : cdft_opt_control%max_ls = 0
116 : cdft_opt_control%build_jacobian = .FALSE.
117 : cdft_opt_control%broyden_update = .FALSE.
118 : cdft_opt_control%continue_ls = .FALSE.
119 : cdft_opt_control%jacobian_restart = .FALSE.
120 : NULLIFY (cdft_opt_control%jacobian_vector)
121 :
122 484 : CALL timestop(handle)
123 :
124 484 : END SUBROUTINE cdft_opt_type_create
125 :
126 : ! **************************************************************************************************
127 : !> \brief releases the CDFT optimizer control object
128 : !> \param cdft_opt_control the object to release
129 : !> \par History
130 : !> 03.2018 created [Nico Holmberg]
131 : !> \author Nico Holmberg
132 : ! **************************************************************************************************
133 17790 : SUBROUTINE cdft_opt_type_release(cdft_opt_control)
134 :
135 : TYPE(cdft_opt_type), POINTER :: cdft_opt_control
136 :
137 17790 : IF (ASSOCIATED(cdft_opt_control)) THEN
138 484 : IF (ASSOCIATED(cdft_opt_control%jacobian_vector)) THEN
139 4 : DEALLOCATE (cdft_opt_control%jacobian_vector)
140 : END IF
141 484 : IF (ALLOCATED(cdft_opt_control%jacobian_step)) THEN
142 484 : DEALLOCATE (cdft_opt_control%jacobian_step)
143 : END IF
144 :
145 484 : DEALLOCATE (cdft_opt_control)
146 : END IF
147 :
148 17790 : NULLIFY (cdft_opt_control)
149 :
150 17790 : END SUBROUTINE cdft_opt_type_release
151 :
152 : ! **************************************************************************************************
153 : !> \brief reads the parameters of the CDFT optimizer type
154 : !> \param cdft_opt_control the object that will contain the values read
155 : !> \param inp_section the input section that contains the values that are read
156 : !> \par History
157 : !> 03.2018 created [Nico Holmberg]
158 : !> \author Nico Holmberg
159 : ! **************************************************************************************************
160 70 : SUBROUTINE cdft_opt_type_read(cdft_opt_control, inp_section)
161 :
162 : TYPE(cdft_opt_type), POINTER :: cdft_opt_control
163 : TYPE(section_vals_type), POINTER :: inp_section
164 :
165 : CHARACTER(LEN=*), PARAMETER :: routineN = 'cdft_opt_type_read'
166 :
167 : INTEGER :: handle
168 70 : INTEGER, DIMENSION(:), POINTER :: tmplist
169 : LOGICAL :: exists
170 70 : REAL(KIND=dp), DIMENSION(:), POINTER :: rtmplist
171 : TYPE(section_vals_type), POINTER :: cdft_opt_section
172 :
173 70 : CALL timeset(routineN, handle)
174 :
175 70 : CPASSERT(ASSOCIATED(cdft_opt_control))
176 70 : cdft_opt_section => section_vals_get_subs_vals(inp_section, "CDFT_OPT")
177 :
178 : CALL section_vals_val_get(cdft_opt_section, "MAX_LS", &
179 70 : i_val=cdft_opt_control%max_ls)
180 : CALL section_vals_val_get(cdft_opt_section, "JACOBIAN_TYPE", &
181 70 : i_val=cdft_opt_control%jacobian_type)
182 : CALL section_vals_val_get(cdft_opt_section, "JACOBIAN_STEP", &
183 70 : r_vals=rtmplist)
184 210 : ALLOCATE (cdft_opt_control%jacobian_step(SIZE(rtmplist)))
185 284 : cdft_opt_control%jacobian_step(:) = rtmplist
186 : CALL section_vals_val_get(cdft_opt_section, "BROYDEN_TYPE", &
187 70 : i_val=cdft_opt_control%broyden_type)
188 : CALL section_vals_val_get(cdft_opt_section, "CONTINUE_LS", &
189 70 : l_val=cdft_opt_control%continue_ls)
190 : CALL section_vals_val_get(cdft_opt_section, "FACTOR_LS", &
191 70 : r_val=cdft_opt_control%factor_ls)
192 70 : IF (cdft_opt_control%factor_ls <= 0.0_dp .OR. &
193 : cdft_opt_control%factor_ls >= 1.0_dp) THEN
194 : CALL cp_abort(__LOCATION__, &
195 0 : "Keyword FACTOR_LS must be between 0.0 and 1.0.")
196 : END IF
197 70 : CALL section_vals_val_get(cdft_opt_section, "JACOBIAN_FREQ", explicit=exists)
198 70 : IF (exists) THEN
199 : CALL section_vals_val_get(cdft_opt_section, "JACOBIAN_FREQ", &
200 64 : i_vals=tmplist)
201 64 : IF (SIZE(tmplist) /= 2) THEN
202 : CALL cp_abort(__LOCATION__, &
203 0 : "Keyword JACOBIAN_FREQ takes exactly two input values.")
204 : END IF
205 192 : IF (ANY(tmplist < 0)) THEN
206 : CALL cp_abort(__LOCATION__, &
207 0 : "Keyword JACOBIAN_FREQ takes only positive values.")
208 : END IF
209 64 : IF (ALL(tmplist == 0)) THEN
210 : CALL cp_abort(__LOCATION__, &
211 0 : "Both values to keyword JACOBIAN_FREQ cannot be zero.")
212 : END IF
213 384 : cdft_opt_control%jacobian_freq(:) = tmplist(1:2)
214 : END IF
215 : CALL section_vals_val_get(cdft_opt_section, "JACOBIAN_RESTART", &
216 70 : l_val=cdft_opt_control%jacobian_restart)
217 70 : IF (cdft_opt_control%jacobian_restart) THEN
218 : CALL section_vals_val_get(cdft_opt_section, "JACOBIAN_VECTOR", &
219 10 : r_vals=rtmplist)
220 30 : ALLOCATE (cdft_opt_control%jacobian_vector(SIZE(rtmplist)))
221 88 : cdft_opt_control%jacobian_vector = rtmplist
222 : END IF
223 :
224 70 : CALL timestop(handle)
225 :
226 140 : END SUBROUTINE cdft_opt_type_read
227 :
228 : ! **************************************************************************************************
229 : !> \brief writes information about the CDFT optimizer object
230 : !> \param cdft_opt_control the CDFT optimizer object
231 : !> \param optimizer the type of optimizer to use
232 : !> \param output_unit the output unit handle
233 : !> \par History
234 : !> 03.2018 created [Nico Holmberg]
235 : !> \author Nico Holmberg
236 : ! **************************************************************************************************
237 60 : SUBROUTINE cdft_opt_type_write(cdft_opt_control, optimizer, output_unit)
238 : TYPE(cdft_opt_type), POINTER :: cdft_opt_control
239 : INTEGER :: optimizer, output_unit
240 :
241 60 : CPASSERT(ASSOCIATED(cdft_opt_control))
242 :
243 73 : SELECT CASE (optimizer)
244 : CASE DEFAULT
245 : ! Do nothing
246 : CASE (outer_scf_optimizer_broyden)
247 13 : WRITE (output_unit, '(T3,A)') "Optimization with Broyden's method"
248 68 : SELECT CASE (cdft_opt_control%broyden_type)
249 : CASE (broyden_type_1)
250 11 : WRITE (output_unit, '(A)') " variant : 1st method"
251 : CASE (broyden_type_1_explicit)
252 1 : WRITE (output_unit, '(A)') " variant : 1st method with explicit initial Jacobian"
253 : CASE (broyden_type_1_ls)
254 0 : WRITE (output_unit, '(A)') " variant : 1st method with backtracking line search"
255 : CASE (broyden_type_1_explicit_ls)
256 : WRITE (output_unit, '(A)') &
257 0 : " variant : 1st method with explicit initial Jacobian"
258 : WRITE (output_unit, '(A)') &
259 0 : " and backtracking line search"
260 : CASE (broyden_type_2)
261 1 : WRITE (output_unit, '(A)') " variant : 2nd method"
262 : CASE (broyden_type_2_explicit)
263 0 : WRITE (output_unit, '(A)') " variant : 2nd method with explicit initial Jacobian"
264 : CASE (broyden_type_2_ls)
265 0 : WRITE (output_unit, '(A)') " variant : 2nd method with backtracking line search"
266 : CASE (broyden_type_2_explicit_ls)
267 : WRITE (output_unit, '(A)') &
268 0 : " variant : 2nd method with explicit initial Jacobian"
269 : WRITE (output_unit, '(A)') &
270 13 : " and backtracking line search"
271 : END SELECT
272 : CASE (outer_scf_optimizer_newton)
273 44 : WRITE (output_unit, '(T3,A)') "Optimization with Newton's method"
274 : CASE (outer_scf_optimizer_newton_ls)
275 60 : WRITE (output_unit, '(T3,A)') "Optimization with Newton's method using backtracking line search"
276 : END SELECT
277 120 : SELECT CASE (optimizer)
278 : CASE DEFAULT
279 : ! Do nothing
280 : CASE (outer_scf_optimizer_broyden, outer_scf_optimizer_newton, outer_scf_optimizer_newton_ls)
281 60 : IF (cdft_opt_control%jacobian_freq(2) > 0) THEN
282 : WRITE (output_unit, '(T6,A,I4,A)') &
283 56 : "The Jacobian is restarted every ", cdft_opt_control%jacobian_freq(2), " energy evaluation"
284 56 : IF (cdft_opt_control%jacobian_freq(1) > 0) THEN
285 : WRITE (output_unit, '(T29,A,I4,A)') &
286 56 : "or every ", cdft_opt_control%jacobian_freq(1), " CDFT SCF iteration"
287 : END IF
288 : ELSE
289 : WRITE (output_unit, '(T6,A,I4,A)') &
290 4 : "The Jacobian is restarted every ", cdft_opt_control%jacobian_freq(1), " CDFT SCF iteration"
291 : END IF
292 : WRITE (output_unit, '(T3,A,F8.4)') &
293 120 : "Optimizer step size: ", cdft_opt_control%newton_step_save
294 : END SELECT
295 :
296 60 : END SUBROUTINE cdft_opt_type_write
297 :
298 : ! **************************************************************************************************
299 : !> \brief copies settings between two CDFT optimizer control objects retaining both
300 : !> \param new the object where to copy the settings
301 : !> \param old the object from where to copy the settings
302 : !> \par History
303 : !> 03.2018 created [Nico Holmberg]
304 : !> \author Nico Holmberg
305 : ! **************************************************************************************************
306 1590 : SUBROUTINE cdft_opt_type_copy(new, old)
307 :
308 : TYPE(cdft_opt_type), POINTER :: new, old
309 :
310 : CHARACTER(LEN=*), PARAMETER :: routineN = 'cdft_opt_type_copy'
311 :
312 : INTEGER :: handle
313 :
314 : ! Do nothing if cdft_opt_type is not allocated
315 : ! this happens if CDFT is performed with an optimizer other than Broyden/Newton
316 1590 : IF (.NOT. ASSOCIATED(old)) RETURN
317 :
318 758 : CALL timeset(routineN, handle)
319 :
320 758 : IF (.NOT. ASSOCIATED(new)) CALL cdft_opt_type_create(new)
321 758 : new%max_ls = old%max_ls
322 758 : new%continue_ls = old%continue_ls
323 758 : new%factor_ls = old%factor_ls
324 758 : new%jacobian_type = old%jacobian_type
325 3790 : new%jacobian_freq(:) = old%jacobian_freq(:)
326 758 : new%newton_step = old%newton_step
327 758 : new%newton_step_save = old%newton_step_save
328 3790 : new%ijacobian(:) = old%ijacobian(:)
329 758 : new%build_jacobian = old%build_jacobian
330 758 : new%broyden_type = old%broyden_type
331 758 : new%broyden_update = old%broyden_update
332 758 : IF (ALLOCATED(new%jacobian_step)) DEALLOCATE (new%jacobian_step)
333 2274 : ALLOCATE (new%jacobian_step(SIZE(old%jacobian_step)))
334 2334 : new%jacobian_step(:) = old%jacobian_step
335 758 : IF (old%jacobian_restart) THEN
336 : ! Transfer restart vector for inverse Jacobian matrix
337 : ! (qs_calculate_inverse_jacobian handles deallocation of transferred vector)
338 30 : new%jacobian_restart = .TRUE.
339 90 : ALLOCATE (new%jacobian_vector(SIZE(old%jacobian_vector)))
340 234 : new%jacobian_vector = old%jacobian_vector
341 30 : DEALLOCATE (old%jacobian_vector)
342 30 : old%jacobian_restart = .FALSE.
343 : END IF
344 :
345 758 : CALL timestop(handle)
346 :
347 758 : END SUBROUTINE cdft_opt_type_copy
348 :
349 0 : END MODULE qs_cdft_opt_types
|