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 : MODULE optimize_input
8 : USE cell_types, ONLY: parse_cell_line
9 : USE cp2k_info, ONLY: write_restart_header
10 : USE cp_external_control, ONLY: external_control
11 : USE cp_log_handling, ONLY: cp_get_default_logger,&
12 : cp_logger_get_default_io_unit,&
13 : cp_logger_type
14 : USE cp_output_handling, ONLY: cp_add_iter_level,&
15 : cp_iterate,&
16 : cp_print_key_finished_output,&
17 : cp_print_key_unit_nr,&
18 : cp_rm_iter_level
19 : USE cp_parser_methods, ONLY: parser_read_line
20 : USE cp_parser_types, ONLY: cp_parser_type,&
21 : parser_create,&
22 : parser_release
23 : USE environment, ONLY: cp2k_get_walltime
24 : USE f77_interface, ONLY: calc_force,&
25 : create_force_env,&
26 : destroy_force_env,&
27 : set_cell
28 : USE input_constants, ONLY: opt_force_matching
29 : USE input_section_types, ONLY: section_type,&
30 : section_vals_get,&
31 : section_vals_get_subs_vals,&
32 : section_vals_type,&
33 : section_vals_val_get,&
34 : section_vals_val_set,&
35 : section_vals_write
36 : USE kinds, ONLY: default_path_length,&
37 : default_string_length,&
38 : dp
39 : USE machine, ONLY: m_flush,&
40 : m_walltime
41 : USE memory_utilities, ONLY: reallocate
42 : USE message_passing, ONLY: mp_comm_type,&
43 : mp_para_env_type
44 : USE parallel_rng_types, ONLY: UNIFORM,&
45 : rng_stream_type
46 : USE physcon, ONLY: bohr
47 : USE powell, ONLY: opt_state_type,&
48 : powell_optimize
49 : #include "./base/base_uses.f90"
50 :
51 : IMPLICIT NONE
52 : PRIVATE
53 :
54 : PUBLIC :: run_optimize_input
55 :
56 : TYPE fm_env_type
57 : CHARACTER(LEN=default_path_length) :: optimize_file_name = ""
58 :
59 : CHARACTER(LEN=default_path_length) :: ref_traj_file_name = ""
60 : CHARACTER(LEN=default_path_length) :: ref_force_file_name = ""
61 : CHARACTER(LEN=default_path_length) :: ref_cell_file_name = ""
62 :
63 : INTEGER :: group_size = -1
64 :
65 : REAL(KIND=dp) :: energy_weight = -1.0_dp
66 : REAL(KIND=dp) :: shift_mm = -1.0_dp
67 : REAL(KIND=dp) :: shift_qm = -1.0_dp
68 : LOGICAL :: shift_average = .FALSE.
69 : INTEGER :: frame_start = -1, frame_stop = -1, frame_stride = -1, frame_count = -1
70 : END TYPE
71 :
72 : TYPE variable_type
73 : CHARACTER(LEN=default_string_length) :: label = ""
74 : REAL(KIND=dp) :: value = -1.0_dp
75 : LOGICAL :: fixed = .FALSE.
76 : END TYPE
77 :
78 : TYPE oi_env_type
79 : INTEGER :: method = -1
80 : INTEGER :: seed = -1
81 : CHARACTER(LEN=default_path_length) :: project_name = ""
82 : TYPE(fm_env_type) :: fm_env = fm_env_type()
83 : TYPE(variable_type), DIMENSION(:), ALLOCATABLE :: variables
84 : REAL(KIND=dp) :: rhobeg = -1.0_dp, rhoend = -1.0_dp
85 : INTEGER :: maxfun = -1
86 : INTEGER :: iter_start_val = -1
87 : REAL(KIND=dp) :: randomize_variables = -1.0_dp
88 : REAL(KIND=dp) :: start_time = -1.0_dp, target_time = -1.0_dp
89 : END TYPE
90 :
91 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'optimize_input'
92 :
93 : CONTAINS
94 :
95 : ! **************************************************************************************************
96 : !> \brief main entry point for methods aimed at optimizing parameters in a CP2K input file
97 : !> \param input_declaration ...
98 : !> \param root_section ...
99 : !> \param para_env ...
100 : !> \author Joost VandeVondele
101 : ! **************************************************************************************************
102 6 : SUBROUTINE run_optimize_input(input_declaration, root_section, para_env)
103 : TYPE(section_type), POINTER :: input_declaration
104 : TYPE(section_vals_type), POINTER :: root_section
105 : TYPE(mp_para_env_type), POINTER :: para_env
106 :
107 : CHARACTER(len=*), PARAMETER :: routineN = 'run_optimize_input'
108 :
109 : INTEGER :: handle, i_var
110 : REAL(KIND=dp) :: random_number, seed(3, 2)
111 6 : TYPE(oi_env_type) :: oi_env
112 6 : TYPE(rng_stream_type), ALLOCATABLE :: rng_stream
113 :
114 6 : CALL timeset(routineN, handle)
115 :
116 6 : oi_env%start_time = m_walltime()
117 :
118 6 : CALL parse_input(oi_env, root_section)
119 :
120 : ! if we have been asked to randomize the variables, we do this.
121 6 : IF (oi_env%randomize_variables .NE. 0.0_dp) THEN
122 36 : seed = REAL(oi_env%seed, KIND=dp)
123 4 : rng_stream = rng_stream_type("run_optimize_input", distribution_type=UNIFORM, seed=seed)
124 12 : DO i_var = 1, SIZE(oi_env%variables, 1)
125 12 : IF (.NOT. oi_env%variables(i_var)%fixed) THEN
126 : ! change with a random percentage the variable
127 8 : random_number = rng_stream%next()
128 : oi_env%variables(i_var)%value = oi_env%variables(i_var)%value* &
129 8 : (1.0_dp + (2*random_number - 1.0_dp)*oi_env%randomize_variables/100.0_dp)
130 : END IF
131 : END DO
132 : END IF
133 :
134 : ! proceed to actual methods
135 12 : SELECT CASE (oi_env%method)
136 : CASE (opt_force_matching)
137 6 : CALL force_matching(oi_env, input_declaration, root_section, para_env)
138 : CASE DEFAULT
139 6 : CPABORT("")
140 : END SELECT
141 :
142 6 : CALL timestop(handle)
143 :
144 6 : END SUBROUTINE run_optimize_input
145 :
146 : ! **************************************************************************************************
147 : !> \brief optimizes parameters by force/energy matching results against reference values
148 : !> \param oi_env ...
149 : !> \param input_declaration ...
150 : !> \param root_section ...
151 : !> \param para_env ...
152 : !> \author Joost VandeVondele
153 : ! **************************************************************************************************
154 6 : SUBROUTINE force_matching(oi_env, input_declaration, root_section, para_env)
155 : TYPE(oi_env_type) :: oi_env
156 : TYPE(section_type), POINTER :: input_declaration
157 : TYPE(section_vals_type), POINTER :: root_section
158 : TYPE(mp_para_env_type), POINTER :: para_env
159 :
160 : CHARACTER(len=*), PARAMETER :: routineN = 'force_matching'
161 :
162 : CHARACTER(len=default_path_length) :: input_path, output_path
163 : CHARACTER(len=default_string_length), &
164 6 : ALLOCATABLE, DIMENSION(:, :) :: initial_variables
165 : INTEGER :: color, energies_unit, handle, history_unit, i_atom, i_el, i_frame, i_free_var, &
166 : i_var, ierr, mepos_master, mepos_minion, n_atom, n_el, n_frames, n_free_var, n_groups, &
167 : n_var, new_env_id, num_pe_master, output_unit, restart_unit, state
168 6 : INTEGER, ALLOCATABLE, DIMENSION(:) :: free_var_index
169 6 : INTEGER, DIMENSION(:), POINTER :: group_distribution
170 : LOGICAL :: should_stop
171 : REAL(KIND=dp) :: e1, e2, e3, e4, e_pot, energy_weight, &
172 : re, rf, shift_mm, shift_qm, t1, t2, &
173 : t3, t4, t5
174 6 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: force, free_vars, pos
175 6 : REAL(KIND=dp), DIMENSION(:), POINTER :: energy_traj, energy_traj_read, energy_var
176 6 : REAL(KIND=dp), DIMENSION(:, :, :), POINTER :: cell_traj, cell_traj_read, force_traj, &
177 6 : force_traj_read, force_var, pos_traj, &
178 6 : pos_traj_read
179 : TYPE(cp_logger_type), POINTER :: logger
180 : TYPE(mp_comm_type) :: mpi_comm_master, mpi_comm_minion, &
181 : mpi_comm_minion_primus
182 : TYPE(opt_state_type) :: ostate
183 : TYPE(section_vals_type), POINTER :: oi_section, variable_section
184 :
185 6 : CALL timeset(routineN, handle)
186 :
187 6 : logger => cp_get_default_logger()
188 6 : CALL cp_add_iter_level(logger%iter_info, "POWELL_OPT")
189 6 : output_unit = cp_logger_get_default_io_unit(logger)
190 :
191 6 : IF (output_unit > 0) THEN
192 3 : WRITE (output_unit, '(T2,A)') 'FORCE_MATCHING| good morning....'
193 : END IF
194 :
195 : ! do IO of ref traj / frc / cell
196 6 : NULLIFY (cell_traj)
197 6 : NULLIFY (cell_traj_read, force_traj_read, pos_traj_read, energy_traj_read)
198 6 : CALL read_reference_data(oi_env, para_env, force_traj_read, pos_traj_read, energy_traj_read, cell_traj_read)
199 6 : n_atom = SIZE(pos_traj_read, 2)
200 :
201 : ! adjust read data with respect to start/stop/stride
202 6 : IF (oi_env%fm_env%frame_stop < 0) oi_env%fm_env%frame_stop = SIZE(pos_traj_read, 3)
203 :
204 6 : IF (oi_env%fm_env%frame_count > 0) THEN
205 : oi_env%fm_env%frame_stride = (oi_env%fm_env%frame_stop - oi_env%fm_env%frame_start + 1 + &
206 0 : oi_env%fm_env%frame_count - 1)/(oi_env%fm_env%frame_count)
207 : END IF
208 6 : n_frames = (oi_env%fm_env%frame_stop - oi_env%fm_env%frame_start + oi_env%fm_env%frame_stride)/oi_env%fm_env%frame_stride
209 :
210 48 : ALLOCATE (force_traj(3, n_atom, n_frames), pos_traj(3, n_atom, n_frames), energy_traj(n_frames))
211 18 : IF (ASSOCIATED(cell_traj_read)) ALLOCATE (cell_traj(3, 3, n_frames))
212 :
213 6 : n_frames = 0
214 220 : DO i_frame = oi_env%fm_env%frame_start, oi_env%fm_env%frame_stop, oi_env%fm_env%frame_stride
215 214 : n_frames = n_frames + 1
216 13910 : force_traj(:, :, n_frames) = force_traj_read(:, :, i_frame)
217 13910 : pos_traj(:, :, n_frames) = pos_traj_read(:, :, i_frame)
218 214 : energy_traj(n_frames) = energy_traj_read(i_frame)
219 5356 : IF (ASSOCIATED(cell_traj)) cell_traj(:, :, n_frames) = cell_traj_read(:, :, i_frame)
220 : END DO
221 6 : DEALLOCATE (force_traj_read, pos_traj_read, energy_traj_read)
222 6 : IF (ASSOCIATED(cell_traj_read)) DEALLOCATE (cell_traj_read)
223 :
224 6 : n_el = 3*n_atom
225 24 : ALLOCATE (pos(n_el), force(n_el))
226 36 : ALLOCATE (energy_var(n_frames), force_var(3, n_atom, n_frames))
227 :
228 : ! split the para_env in a set of sub_para_envs that will do the force_env communications
229 6 : mpi_comm_master = para_env
230 6 : num_pe_master = para_env%num_pe
231 6 : mepos_master = para_env%mepos
232 18 : ALLOCATE (group_distribution(0:num_pe_master - 1))
233 6 : IF (oi_env%fm_env%group_size > para_env%num_pe) oi_env%fm_env%group_size = para_env%num_pe
234 :
235 6 : CALL mpi_comm_minion%from_split(mpi_comm_master, n_groups, group_distribution, subgroup_min_size=oi_env%fm_env%group_size)
236 6 : mepos_minion = mpi_comm_minion%mepos
237 6 : color = 0
238 6 : IF (mepos_minion == 0) color = 1
239 6 : CALL mpi_comm_minion_primus%from_split(mpi_comm_master, color)
240 :
241 : ! assign initial variables
242 6 : n_var = SIZE(oi_env%variables, 1)
243 18 : ALLOCATE (initial_variables(2, n_var))
244 6 : n_free_var = 0
245 18 : DO i_var = 1, n_var
246 12 : initial_variables(1, i_var) = oi_env%variables(i_var)%label
247 12 : WRITE (initial_variables(2, i_var), *) oi_env%variables(i_var)%value
248 18 : IF (.NOT. oi_env%variables(i_var)%fixed) n_free_var = n_free_var + 1
249 : END DO
250 30 : ALLOCATE (free_vars(n_free_var), free_var_index(n_free_var))
251 18 : i_free_var = 0
252 18 : DO i_var = 1, n_var
253 18 : IF (.NOT. oi_env%variables(i_var)%fixed) THEN
254 12 : i_free_var = i_free_var + 1
255 12 : free_var_index(i_free_var) = i_var
256 12 : free_vars(i_free_var) = oi_env%variables(free_var_index(i_free_var))%value
257 : END IF
258 : END DO
259 :
260 : ! create input and output file names.
261 6 : input_path = oi_env%fm_env%optimize_file_name
262 6 : WRITE (output_path, '(A,I0,A)') TRIM(oi_env%project_name)//"-worker-", group_distribution(mepos_master), ".out"
263 :
264 : ! initialize the powell optimizer
265 6 : energy_weight = oi_env%fm_env%energy_weight
266 6 : shift_mm = oi_env%fm_env%shift_mm
267 6 : shift_qm = oi_env%fm_env%shift_qm
268 :
269 6 : IF (para_env%is_source()) THEN
270 3 : ostate%nf = 0
271 3 : ostate%nvar = n_free_var
272 3 : ostate%rhoend = oi_env%rhoend
273 3 : ostate%rhobeg = oi_env%rhobeg
274 3 : ostate%maxfun = oi_env%maxfun
275 3 : ostate%iprint = 1
276 3 : ostate%unit = output_unit
277 3 : ostate%state = 0
278 : END IF
279 :
280 6 : IF (output_unit > 0) THEN
281 3 : WRITE (output_unit, '(T2,A,T60,I20)') 'FORCE_MATCHING| number of atoms per frame ', n_atom
282 3 : WRITE (output_unit, '(T2,A,T60,I20)') 'FORCE_MATCHING| number of frames ', n_frames
283 3 : WRITE (output_unit, '(T2,A,T60,I20)') 'FORCE_MATCHING| number of parallel groups ', n_groups
284 3 : WRITE (output_unit, '(T2,A,T60,I20)') 'FORCE_MATCHING| number of variables ', n_var
285 3 : WRITE (output_unit, '(T2,A,T60,I20)') 'FORCE_MATCHING| number of free variables ', n_free_var
286 3 : WRITE (output_unit, '(T2,A,A)') 'FORCE_MATCHING| optimize file name ', TRIM(input_path)
287 3 : WRITE (output_unit, '(T2,A,T60,F20.12)') 'FORCE_MATCHING| accuracy', ostate%rhoend
288 3 : WRITE (output_unit, '(T2,A,T60,F20.12)') 'FORCE_MATCHING| step size', ostate%rhobeg
289 3 : WRITE (output_unit, '(T2,A,T60,I20)') 'FORCE_MATCHING| max function evaluation', ostate%maxfun
290 3 : WRITE (output_unit, '(T2,A,T60,L20)') 'FORCE_MATCHING| shift average', oi_env%fm_env%shift_average
291 3 : WRITE (output_unit, '(T2,A)') 'FORCE_MATCHING| initial values:'
292 9 : DO i_var = 1, n_var
293 9 : WRITE (output_unit, '(T2,A,1X,E28.16)') TRIM(oi_env%variables(i_var)%label), oi_env%variables(i_var)%value
294 : END DO
295 3 : WRITE (output_unit, '(T2,A)') 'FORCE_MATCHING| switching to POWELL optimization of the free parameters'
296 3 : WRITE (output_unit, '()')
297 3 : WRITE (output_unit, '(T2,A20,A20,A11,A11)') 'iteration number', 'function value', 'time', 'time Force'
298 3 : CALL m_flush(output_unit)
299 : END IF
300 :
301 6 : t1 = m_walltime()
302 :
303 98 : DO
304 :
305 : ! globalize the state
306 104 : IF (para_env%is_source()) state = ostate%state
307 104 : CALL para_env%bcast(state)
308 :
309 : ! if required get the energy of this set of params
310 104 : IF (state == 2) THEN
311 :
312 86 : CALL cp_iterate(logger%iter_info, last=.FALSE.)
313 :
314 : ! create a new force env, updating the free vars as needed
315 258 : DO i_free_var = 1, n_free_var
316 172 : WRITE (initial_variables(2, free_var_index(i_free_var)), *) free_vars(i_free_var)
317 258 : oi_env%variables(free_var_index(i_free_var))%value = free_vars(i_free_var)
318 : END DO
319 :
320 : ierr = 0
321 : CALL create_force_env(new_env_id=new_env_id, input_declaration=input_declaration, &
322 : input_path=input_path, output_path=output_path, &
323 86 : mpi_comm=mpi_comm_minion, initial_variables=initial_variables, ierr=ierr)
324 :
325 : ! set to zero initialy, for easier mp_summing
326 3460 : energy_var = 0.0_dp
327 111428 : force_var = 0.0_dp
328 :
329 : ! compute energies and forces for all frames, doing the work on a minion sub group based on round robin
330 86 : t5 = 0.0_dp
331 3460 : DO i_frame = group_distribution(mepos_master) + 1, n_frames, n_groups
332 :
333 : ! set new cell if needed
334 3374 : IF (ASSOCIATED(cell_traj)) THEN
335 3374 : CALL set_cell(env_id=new_env_id, new_cell=cell_traj(:, :, i_frame), ierr=ierr)
336 : END IF
337 :
338 : ! copy pos from ref
339 : i_el = 0
340 30366 : DO i_atom = 1, n_atom
341 26992 : pos(i_el + 1) = pos_traj(1, i_atom, i_frame)
342 26992 : pos(i_el + 2) = pos_traj(2, i_atom, i_frame)
343 26992 : pos(i_el + 3) = pos_traj(3, i_atom, i_frame)
344 30366 : i_el = i_el + 3
345 : END DO
346 :
347 : ! evaluate energy/force with new pos
348 3374 : t3 = m_walltime()
349 3374 : CALL calc_force(env_id=new_env_id, pos=pos, n_el_pos=n_el, e_pot=e_pot, force=force, n_el_force=n_el, ierr=ierr)
350 3374 : t4 = m_walltime()
351 3374 : t5 = t5 + t4 - t3
352 :
353 : ! copy force and energy in place
354 3374 : energy_var(i_frame) = e_pot
355 3374 : i_el = 0
356 33826 : DO i_atom = 1, n_atom
357 26992 : force_var(1, i_atom, i_frame) = force(i_el + 1)
358 26992 : force_var(2, i_atom, i_frame) = force(i_el + 2)
359 26992 : force_var(3, i_atom, i_frame) = force(i_el + 3)
360 30366 : i_el = i_el + 3
361 : END DO
362 :
363 : END DO
364 :
365 : ! clean up force env, get ready for the next round
366 86 : CALL destroy_force_env(env_id=new_env_id, ierr=ierr)
367 :
368 : ! get data everywhere on the master group, we could reduce the amount of data by reducing to partial RMSD first
369 : ! furthermore, we should only do this operation among the masters of the minion group
370 86 : IF (mepos_minion == 0) THEN
371 3417 : CALL mpi_comm_minion_primus%sum(energy_var)
372 111385 : CALL mpi_comm_minion_primus%sum(force_var)
373 : END IF
374 :
375 : ! now evaluate the target function to be minimized (only valid on mepos_minion==0)
376 86 : IF (para_env%is_source()) THEN
377 55714 : rf = SQRT(SUM((force_var - force_traj)**2)/(REAL(n_frames, KIND=dp)*REAL(n_atom, KIND=dp)))
378 43 : IF (oi_env%fm_env%shift_average) THEN
379 0 : shift_mm = SUM(energy_var)/n_frames
380 0 : shift_qm = SUM(energy_traj)/n_frames
381 : END IF
382 1730 : re = SQRT(SUM(((energy_var - shift_mm) - (energy_traj - shift_qm))**2)/n_frames)
383 43 : ostate%f = energy_weight*re + rf
384 43 : t2 = m_walltime()
385 43 : WRITE (output_unit, '(T2,I20,F20.12,F11.3,F11.3)') oi_env%iter_start_val + ostate%nf, ostate%f, t2 - t1, t5
386 43 : CALL m_flush(output_unit)
387 43 : t1 = m_walltime()
388 : END IF
389 :
390 : ! the history file with the trajectory of the parameters
391 : history_unit = cp_print_key_unit_nr(logger, root_section, "OPTIMIZE_INPUT%HISTORY", &
392 86 : extension=".dat")
393 86 : IF (history_unit > 0) THEN
394 8 : WRITE (UNIT=history_unit, FMT="(I20,F20.12,1000F20.12)") oi_env%iter_start_val + ostate%nf, ostate%f, free_vars
395 : END IF
396 86 : CALL cp_print_key_finished_output(history_unit, logger, root_section, "OPTIMIZE_INPUT%HISTORY")
397 :
398 : ! the energy profile for all frames
399 : energies_unit = cp_print_key_unit_nr(logger, root_section, "OPTIMIZE_INPUT%FORCE_MATCHING%COMPARE_ENERGIES", &
400 86 : file_position="REWIND", extension=".dat")
401 86 : IF (energies_unit > 0) THEN
402 8 : WRITE (UNIT=energies_unit, FMT="(A20,A20,A20,A20)") "#frame", "ref", "fit", "diff"
403 324 : DO i_frame = 1, n_frames
404 316 : e1 = energy_traj(i_frame) - shift_qm
405 316 : e2 = energy_var(i_frame) - shift_mm
406 324 : WRITE (UNIT=energies_unit, FMT="(I20,F20.12,F20.12,F20.12)") i_frame, e1, e2, e1 - e2
407 : END DO
408 : END IF
409 86 : CALL cp_print_key_finished_output(energies_unit, logger, root_section, "OPTIMIZE_INPUT%FORCE_MATCHING%COMPARE_ENERGIES")
410 :
411 : ! the force profile for all frames
412 : energies_unit = cp_print_key_unit_nr(logger, root_section, "OPTIMIZE_INPUT%FORCE_MATCHING%COMPARE_FORCES", &
413 86 : file_position="REWIND", extension=".dat")
414 86 : IF (energies_unit > 0) THEN
415 43 : WRITE (UNIT=energies_unit, FMT="(A20,A20,A20,A20)") "#frame", "normalized diff", "diff", "ref", "ref sum"
416 1730 : DO i_frame = 1, n_frames
417 55671 : e1 = SQRT(SUM((force_var(:, :, i_frame) - force_traj(:, :, i_frame))**2))
418 55671 : e2 = SQRT(SUM((force_traj(:, :, i_frame))**2))
419 47236 : e3 = SQRT(SUM(SUM(force_traj(:, :, i_frame), DIM=2)**2))
420 47236 : e4 = SQRT(SUM(SUM(force_var(:, :, i_frame), DIM=2)**2))
421 1730 : WRITE (UNIT=energies_unit, FMT="(I20,F20.12,F20.12,F20.12,2F20.12)") i_frame, e1/e2, e1, e2, e3, e4
422 : END DO
423 : END IF
424 86 : CALL cp_print_key_finished_output(energies_unit, logger, root_section, "OPTIMIZE_INPUT%FORCE_MATCHING%COMPARE_FORCES")
425 :
426 : ! a restart file with the current values of the parameters
427 : restart_unit = cp_print_key_unit_nr(logger, root_section, "OPTIMIZE_INPUT%RESTART", extension=".restart", &
428 86 : file_position="REWIND", do_backup=.TRUE.)
429 86 : IF (restart_unit > 0) THEN
430 8 : oi_section => section_vals_get_subs_vals(root_section, "OPTIMIZE_INPUT")
431 8 : CALL section_vals_val_set(oi_section, "ITER_START_VAL", i_val=oi_env%iter_start_val + ostate%nf)
432 8 : variable_section => section_vals_get_subs_vals(oi_section, "VARIABLE")
433 24 : DO i_free_var = 1, n_free_var
434 : CALL section_vals_val_set(variable_section, "VALUE", i_rep_section=free_var_index(i_free_var), &
435 24 : r_val=free_vars(i_free_var))
436 : END DO
437 8 : CALL write_restart_header(restart_unit)
438 8 : CALL section_vals_write(root_section, unit_nr=restart_unit, hide_root=.TRUE.)
439 : END IF
440 86 : CALL cp_print_key_finished_output(restart_unit, logger, root_section, "OPTIMIZE_INPUT%RESTART")
441 :
442 : END IF
443 :
444 104 : IF (state == -1) EXIT
445 :
446 98 : CALL external_control(should_stop, "OPTIMIZE_INPUT", target_time=oi_env%target_time, start_time=oi_env%start_time)
447 :
448 98 : IF (should_stop) EXIT
449 :
450 : ! do a powell step if needed
451 98 : IF (para_env%is_source()) THEN
452 49 : CALL powell_optimize(ostate%nvar, free_vars, ostate)
453 : END IF
454 104 : CALL para_env%bcast(free_vars)
455 :
456 : END DO
457 :
458 : ! finally, get the best set of variables
459 6 : IF (para_env%is_source()) THEN
460 3 : ostate%state = 8
461 3 : CALL powell_optimize(ostate%nvar, free_vars, ostate)
462 : END IF
463 6 : CALL para_env%bcast(free_vars)
464 18 : DO i_free_var = 1, n_free_var
465 12 : WRITE (initial_variables(2, free_var_index(i_free_var)), *) free_vars(i_free_var)
466 18 : oi_env%variables(free_var_index(i_free_var))%value = free_vars(i_free_var)
467 : END DO
468 6 : IF (para_env%is_source()) THEN
469 3 : WRITE (output_unit, '(T2,A)') ''
470 3 : WRITE (output_unit, '(T2,A,T60,F20.12)') 'FORCE_MATCHING| optimal function value found so far:', ostate%fopt
471 3 : WRITE (output_unit, '(T2,A)') 'FORCE_MATCHING| optimal variables found so far:'
472 9 : DO i_var = 1, n_var
473 9 : WRITE (output_unit, '(T2,A,1X,E28.16)') TRIM(oi_env%variables(i_var)%label), oi_env%variables(i_var)%value
474 : END DO
475 : END IF
476 :
477 6 : CALL cp_rm_iter_level(logger%iter_info, "POWELL_OPT")
478 :
479 : ! deallocate for cleanup
480 6 : IF (ASSOCIATED(cell_traj)) DEALLOCATE (cell_traj)
481 6 : DEALLOCATE (pos, force, force_traj, pos_traj, force_var)
482 6 : DEALLOCATE (group_distribution, energy_traj, energy_var)
483 6 : CALL mpi_comm_minion%free()
484 6 : CALL mpi_comm_minion_primus%free()
485 :
486 6 : CALL timestop(handle)
487 :
488 12 : END SUBROUTINE force_matching
489 :
490 : ! **************************************************************************************************
491 : !> \brief reads the reference data for force matching results, the format of the files needs to be the CP2K xyz trajectory format
492 : !> \param oi_env ...
493 : !> \param para_env ...
494 : !> \param force_traj forces
495 : !> \param pos_traj position
496 : !> \param energy_traj energies, as extracted from the forces file
497 : !> \param cell_traj cell parameters, as extracted from a CP2K cell file
498 : !> \author Joost VandeVondele
499 : ! **************************************************************************************************
500 24 : SUBROUTINE read_reference_data(oi_env, para_env, force_traj, pos_traj, energy_traj, cell_traj)
501 : TYPE(oi_env_type) :: oi_env
502 : TYPE(mp_para_env_type), POINTER :: para_env
503 : REAL(KIND=dp), DIMENSION(:, :, :), POINTER :: force_traj, pos_traj
504 : REAL(KIND=dp), DIMENSION(:), POINTER :: energy_traj
505 : REAL(KIND=dp), DIMENSION(:, :, :), POINTER :: cell_traj
506 :
507 : CHARACTER(len=*), PARAMETER :: routineN = 'read_reference_data'
508 :
509 : CHARACTER(len=default_path_length) :: filename
510 : CHARACTER(len=default_string_length) :: AA
511 : INTEGER :: cell_itimes, handle, i, iframe, &
512 : n_frames, n_frames_current, nread, &
513 : trj_itimes
514 : LOGICAL :: at_end, test_ok
515 : REAL(KIND=dp) :: cell_time, trj_epot, trj_time, vec(3), &
516 : vol
517 : TYPE(cp_parser_type) :: local_parser
518 :
519 6 : CALL timeset(routineN, handle)
520 :
521 : ! do IO of ref traj / frc / cell
522 :
523 : ! trajectory
524 6 : n_frames = 0
525 6 : n_frames_current = 0
526 6 : NULLIFY (pos_traj, energy_traj, force_traj)
527 6 : filename = oi_env%fm_env%ref_traj_file_name
528 6 : IF (filename .EQ. "") &
529 0 : CPABORT("The reference trajectory file name is empty")
530 6 : CALL parser_create(local_parser, filename, para_env=para_env)
531 : DO
532 312 : CALL parser_read_line(local_parser, 1, at_end=at_end)
533 312 : IF (at_end) EXIT
534 306 : READ (local_parser%input_line, FMT="(I8)") nread
535 306 : n_frames = n_frames + 1
536 :
537 306 : IF (n_frames > n_frames_current) THEN
538 18 : n_frames_current = 5*(n_frames_current + 10)/3
539 18 : CALL reallocate(pos_traj, 1, 3, 1, nread, 1, n_frames_current)
540 : END IF
541 :
542 : ! title line
543 306 : CALL parser_read_line(local_parser, 1)
544 :
545 : ! actual coordinates
546 2760 : DO i = 1, nread
547 2448 : CALL parser_read_line(local_parser, 1)
548 2448 : READ (local_parser%input_line(1:LEN_TRIM(local_parser%input_line)), *) AA, vec
549 10098 : pos_traj(:, i, n_frames) = vec*bohr
550 : END DO
551 :
552 : END DO
553 6 : CALL parser_release(local_parser)
554 :
555 6 : n_frames_current = n_frames
556 6 : CALL reallocate(energy_traj, 1, n_frames_current)
557 6 : CALL reallocate(force_traj, 1, 3, 1, nread, 1, n_frames_current)
558 6 : CALL reallocate(pos_traj, 1, 3, 1, nread, 1, n_frames_current)
559 :
560 : ! now force reference trajectory
561 6 : filename = oi_env%fm_env%ref_force_file_name
562 6 : IF (filename .EQ. "") &
563 0 : CPABORT("The reference force file name is empty")
564 6 : CALL parser_create(local_parser, filename, para_env=para_env)
565 312 : DO iframe = 1, n_frames
566 306 : CALL parser_read_line(local_parser, 1)
567 306 : READ (local_parser%input_line, FMT="(I8)") nread
568 :
569 : ! title line
570 306 : test_ok = .FALSE.
571 306 : CALL parser_read_line(local_parser, 1)
572 306 : READ (local_parser%input_line, FMT="(T6,I8,T23,F12.3,T41,F20.10)", ERR=999) trj_itimes, trj_time, trj_epot
573 : test_ok = .TRUE.
574 : 999 CONTINUE
575 : IF (.NOT. test_ok) THEN
576 0 : CPABORT("Could not parse the title line of the trajectory file")
577 : END IF
578 306 : energy_traj(iframe) = trj_epot
579 :
580 : ! actual forces, in a.u.
581 2760 : DO i = 1, nread
582 2448 : CALL parser_read_line(local_parser, 1)
583 2448 : READ (local_parser%input_line(1:LEN_TRIM(local_parser%input_line)), *) AA, vec
584 10098 : force_traj(:, i, iframe) = vec
585 : END DO
586 : END DO
587 6 : CALL parser_release(local_parser)
588 :
589 : ! and cell, which is optional
590 6 : NULLIFY (cell_traj)
591 6 : filename = oi_env%fm_env%ref_cell_file_name
592 6 : IF (filename .NE. "") THEN
593 6 : CALL parser_create(local_parser, filename, para_env=para_env)
594 18 : ALLOCATE (cell_traj(3, 3, n_frames))
595 312 : DO iframe = 1, n_frames
596 306 : CALL parser_read_line(local_parser, 1)
597 312 : CALL parse_cell_line(local_parser%input_line, cell_itimes, cell_time, cell_traj(:, :, iframe), vol)
598 : END DO
599 12 : CALL parser_release(local_parser)
600 : END IF
601 :
602 6 : CALL timestop(handle)
603 :
604 18 : END SUBROUTINE read_reference_data
605 :
606 : ! **************************************************************************************************
607 : !> \brief parses the input section, and stores in the optimize input environment
608 : !> \param oi_env optimize input environment
609 : !> \param root_section ...
610 : !> \author Joost VandeVondele
611 : ! **************************************************************************************************
612 12 : SUBROUTINE parse_input(oi_env, root_section)
613 : TYPE(oi_env_type) :: oi_env
614 : TYPE(section_vals_type), POINTER :: root_section
615 :
616 : CHARACTER(len=*), PARAMETER :: routineN = 'parse_input'
617 :
618 : INTEGER :: handle, ivar, n_var
619 : LOGICAL :: explicit
620 : TYPE(section_vals_type), POINTER :: fm_section, oi_section, variable_section
621 :
622 6 : CALL timeset(routineN, handle)
623 :
624 6 : CALL section_vals_val_get(root_section, "GLOBAL%PROJECT", c_val=oi_env%project_name)
625 6 : CALL section_vals_val_get(root_section, "GLOBAL%SEED", i_val=oi_env%seed)
626 : CALL cp2k_get_walltime(section=root_section, keyword_name="GLOBAL%WALLTIME", &
627 6 : walltime=oi_env%target_time)
628 :
629 6 : oi_section => section_vals_get_subs_vals(root_section, "OPTIMIZE_INPUT")
630 6 : variable_section => section_vals_get_subs_vals(oi_section, "VARIABLE")
631 :
632 6 : CALL section_vals_val_get(oi_section, "ACCURACY", r_val=oi_env%rhoend)
633 6 : CALL section_vals_val_get(oi_section, "STEP_SIZE", r_val=oi_env%rhobeg)
634 6 : CALL section_vals_val_get(oi_section, "MAX_FUN", i_val=oi_env%maxfun)
635 6 : CALL section_vals_val_get(oi_section, "ITER_START_VAL", i_val=oi_env%iter_start_val)
636 6 : CALL section_vals_val_get(oi_section, "RANDOMIZE_VARIABLES", r_val=oi_env%randomize_variables)
637 :
638 6 : CALL section_vals_get(variable_section, explicit=explicit, n_repetition=n_var)
639 6 : IF (explicit) THEN
640 30 : ALLOCATE (oi_env%variables(1:n_var))
641 18 : DO ivar = 1, n_var
642 : CALL section_vals_val_get(variable_section, "VALUE", i_rep_section=ivar, &
643 12 : r_val=oi_env%variables(ivar)%value)
644 : CALL section_vals_val_get(variable_section, "FIXED", i_rep_section=ivar, &
645 12 : l_val=oi_env%variables(ivar)%fixed)
646 : CALL section_vals_val_get(variable_section, "LABEL", i_rep_section=ivar, &
647 18 : c_val=oi_env%variables(ivar)%label)
648 : END DO
649 : END IF
650 :
651 6 : CALL section_vals_val_get(oi_section, "METHOD", i_val=oi_env%method)
652 12 : SELECT CASE (oi_env%method)
653 : CASE (opt_force_matching)
654 6 : fm_section => section_vals_get_subs_vals(oi_section, "FORCE_MATCHING")
655 6 : CALL section_vals_val_get(fm_section, "REF_TRAJ_FILE_NAME", c_val=oi_env%fm_env%ref_traj_file_name)
656 6 : CALL section_vals_val_get(fm_section, "REF_FORCE_FILE_NAME", c_val=oi_env%fm_env%ref_force_file_name)
657 6 : CALL section_vals_val_get(fm_section, "REF_CELL_FILE_NAME", c_val=oi_env%fm_env%ref_cell_file_name)
658 6 : CALL section_vals_val_get(fm_section, "OPTIMIZE_FILE_NAME", c_val=oi_env%fm_env%optimize_file_name)
659 6 : CALL section_vals_val_get(fm_section, "FRAME_START", i_val=oi_env%fm_env%frame_start)
660 6 : CALL section_vals_val_get(fm_section, "FRAME_STOP", i_val=oi_env%fm_env%frame_stop)
661 6 : CALL section_vals_val_get(fm_section, "FRAME_STRIDE", i_val=oi_env%fm_env%frame_stride)
662 6 : CALL section_vals_val_get(fm_section, "FRAME_COUNT", i_val=oi_env%fm_env%frame_count)
663 :
664 6 : CALL section_vals_val_get(fm_section, "GROUP_SIZE", i_val=oi_env%fm_env%group_size)
665 :
666 6 : CALL section_vals_val_get(fm_section, "ENERGY_WEIGHT", r_val=oi_env%fm_env%energy_weight)
667 6 : CALL section_vals_val_get(fm_section, "SHIFT_MM", r_val=oi_env%fm_env%shift_mm)
668 6 : CALL section_vals_val_get(fm_section, "SHIFT_QM", r_val=oi_env%fm_env%shift_qm)
669 6 : CALL section_vals_val_get(fm_section, "SHIFT_AVERAGE", l_val=oi_env%fm_env%shift_average)
670 : CASE DEFAULT
671 6 : CPABORT("")
672 : END SELECT
673 :
674 6 : CALL timestop(handle)
675 :
676 6 : END SUBROUTINE parse_input
677 :
678 0 : END MODULE optimize_input
|