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 contains a functional that calculates the energy and its derivatives
10 : !> for the geometry optimizer
11 : !> \par History
12 : !> none
13 : ! **************************************************************************************************
14 : MODULE gopt_f_methods
15 :
16 : USE atomic_kind_list_types, ONLY: atomic_kind_list_type
17 : USE atomic_kind_types, ONLY: atomic_kind_type,&
18 : get_atomic_kind_set
19 : USE bibliography, ONLY: Henkelman1999,&
20 : cite_reference
21 : USE cell_methods, ONLY: cell_create,&
22 : init_cell,&
23 : write_cell
24 : USE cell_opt_utils, ONLY: apply_cell_constraints,&
25 : cell_opt_constraint_label,&
26 : get_dg_dh,&
27 : rescale_new_cell_volume
28 : USE cell_types, ONLY: cell_copy,&
29 : cell_release,&
30 : cell_type,&
31 : real_to_scaled,&
32 : scaled_to_real
33 : USE cp_log_handling, ONLY: cp_to_string
34 : USE cp_subsys_types, ONLY: cp_subsys_get,&
35 : cp_subsys_set,&
36 : cp_subsys_type,&
37 : pack_subsys_particles,&
38 : unpack_subsys_particles
39 : USE cp_units, ONLY: cp_unit_from_cp2k
40 : USE dimer_methods, ONLY: cp_eval_at_ts
41 : USE dimer_types, ONLY: dimer_env_type
42 : USE dimer_utils, ONLY: update_dimer_vec
43 : USE distribution_1d_types, ONLY: distribution_1d_type
44 : USE force_env_methods, ONLY: force_env_calc_energy_force
45 : USE force_env_types, ONLY: force_env_get,&
46 : force_env_get_natom,&
47 : force_env_get_nparticle,&
48 : force_env_type,&
49 : use_qmmm,&
50 : use_qmmmx
51 : USE gopt_f_types, ONLY: gopt_f_type
52 : USE gopt_param_types, ONLY: gopt_param_type
53 : USE input_constants, ONLY: default_cell_method_id,&
54 : default_minimization_method_id,&
55 : default_shellcore_method_id,&
56 : default_ts_method_id,&
57 : fix_none
58 : USE input_cp2k_restarts, ONLY: write_restart
59 : USE input_section_types, ONLY: section_vals_type,&
60 : section_vals_val_get
61 : USE kinds, ONLY: default_string_length,&
62 : dp,&
63 : int_8
64 : USE machine, ONLY: m_flush
65 : USE md_energies, ONLY: sample_memory
66 : USE message_passing, ONLY: mp_para_env_type
67 : USE motion_utils, ONLY: write_simulation_cell,&
68 : write_stress_tensor_to_file,&
69 : write_trajectory
70 : USE particle_list_types, ONLY: particle_list_type
71 : USE particle_methods, ONLY: write_final_structure,&
72 : write_structure_data
73 : USE particle_types, ONLY: particle_type
74 : USE qmmm_util, ONLY: apply_qmmm_translate
75 : USE qmmmx_util, ONLY: apply_qmmmx_translate
76 : USE space_groups, ONLY: identify_space_group,&
77 : print_spgr,&
78 : spgr_apply_rotations_coord,&
79 : spgr_apply_rotations_force,&
80 : spgr_apply_rotations_stress,&
81 : spgr_project_cell_metric,&
82 : spgr_write_stress_tensor
83 : USE space_groups_types, ONLY: spgr_type
84 : USE virial_methods, ONLY: virial_evaluate,&
85 : virial_update
86 : USE virial_types, ONLY: virial_type
87 : #include "../base/base_uses.f90"
88 :
89 : IMPLICIT NONE
90 : PRIVATE
91 :
92 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'gopt_f_methods'
93 : INTEGER(KIND=int_8), PARAMETER, PRIVATE :: bytes_per_mib = 1024*1024
94 :
95 : PUBLIC :: cp_eval_at, &
96 : gopt_f_create_x0, &
97 : gopt_f_project_coord, gopt_f_project_step, gopt_f_project_vector, &
98 : gopt_f_space_group_init, gopt_f_space_group_show, &
99 : print_geo_opt_header, print_geo_opt_nc, &
100 : gopt_f_io_init, gopt_f_io, gopt_f_io_finalize, gopt_f_ii, &
101 : apply_cell_change
102 :
103 : CONTAINS
104 :
105 : ! **************************************************************************************************
106 : !> \brief returns the value of the parameters for the actual configuration
107 : !> \param gopt_env the geometry optimization environment you want the info about
108 : !> x0: the parameter vector (is allocated by this routine)
109 : !> \param x0 ...
110 : !> \par History
111 : !> - Cell optimization revised (06.11.2012,MK)
112 : ! **************************************************************************************************
113 1119 : SUBROUTINE gopt_f_create_x0(gopt_env, x0)
114 :
115 : TYPE(gopt_f_type), POINTER :: gopt_env
116 : REAL(KIND=dp), DIMENSION(:), POINTER :: x0
117 :
118 : INTEGER :: i, idg, j, nparticle
119 : TYPE(cell_type), POINTER :: cell
120 : TYPE(cp_subsys_type), POINTER :: subsys
121 :
122 1119 : NULLIFY (cell)
123 1119 : NULLIFY (subsys)
124 :
125 2004 : SELECT CASE (gopt_env%type_id)
126 : CASE (default_minimization_method_id, default_ts_method_id)
127 885 : CALL force_env_get(gopt_env%force_env, subsys=subsys)
128 : ! before starting we handle the case of translating coordinates (QM/MM)
129 885 : CALL apply_qmmm_translation(gopt_env)
130 885 : nparticle = force_env_get_nparticle(gopt_env%force_env)
131 2655 : ALLOCATE (x0(3*nparticle))
132 885 : CALL pack_subsys_particles(subsys=subsys, r=x0)
133 : CASE (default_cell_method_id)
134 234 : CALL force_env_get(gopt_env%force_env, subsys=subsys, cell=cell)
135 : ! Store reference cell
136 6084 : gopt_env%h_ref = cell%hmat
137 : ! before starting we handle the case of translating coordinates (QM/MM)
138 234 : CALL apply_qmmm_translation(gopt_env)
139 234 : nparticle = force_env_get_nparticle(gopt_env%force_env)
140 702 : ALLOCATE (x0(3*nparticle + 6))
141 234 : CALL pack_subsys_particles(subsys=subsys, r=x0)
142 234 : idg = 3*nparticle
143 936 : DO i = 1, 3
144 2340 : DO j = 1, i
145 1404 : idg = idg + 1
146 2106 : x0(idg) = gopt_env%cell_env%opt_cell%hmat(j, i)
147 : END DO
148 : END DO
149 : CASE DEFAULT
150 1119 : CPABORT("Invalid or not yet implemented type of optimization")
151 : END SELECT
152 :
153 1119 : END SUBROUTINE gopt_f_create_x0
154 :
155 : ! **************************************************************************************************
156 : !> \brief Apply the QM/MM and QM/MM/X coordinate translations before packing x0
157 : !> \param gopt_env ...
158 : ! **************************************************************************************************
159 1119 : SUBROUTINE apply_qmmm_translation(gopt_env)
160 : TYPE(gopt_f_type), POINTER :: gopt_env
161 :
162 1119 : IF (gopt_env%force_env%in_use == use_qmmm) THEN
163 36 : CALL apply_qmmm_translate(gopt_env%force_env%qmmm_env)
164 : END IF
165 1119 : IF (gopt_env%force_env%in_use == use_qmmmx) THEN
166 0 : CALL apply_qmmmx_translate(gopt_env%force_env%qmmmx_env)
167 : END IF
168 1119 : END SUBROUTINE apply_qmmm_translation
169 :
170 : ! **************************************************************************************************
171 : !> \brief evaluete the potential energy and its gradients using an array
172 : !> with same dimension as the particle_set
173 : !> \param gopt_env the geometry optimization environment
174 : !> \param x the position where the function should be evaluated
175 : !> \param f the function value
176 : !> \param gradient the value of its gradient
177 : !> \param master ...
178 : !> \param para_env ...
179 : !> \par History
180 : !> CELL OPTIMIZATION: Teodoro Laino [tlaino] - University of Zurich - 03.2008
181 : !> 07.2020 Pierre Cazade [pcazade] Space Group Symmetry
182 : !> \author Teodoro Laino [tlaino] - University of Zurich - 01.2008
183 : ! **************************************************************************************************
184 17045 : SUBROUTINE cp_eval_at(gopt_env, x, f, gradient, master, &
185 : para_env)
186 :
187 : TYPE(gopt_f_type), POINTER :: gopt_env
188 : REAL(KIND=dp), DIMENSION(:), POINTER :: x
189 : REAL(KIND=dp), INTENT(OUT), OPTIONAL :: f
190 : REAL(KIND=dp), DIMENSION(:), OPTIONAL, POINTER :: gradient
191 : INTEGER, INTENT(IN) :: master
192 : TYPE(mp_para_env_type), POINTER :: para_env
193 :
194 : CHARACTER(len=*), PARAMETER :: routineN = 'cp_eval_at'
195 :
196 : INTEGER :: handle, idg, idir, ip, nparticle, nsize, &
197 : shell_index
198 : REAL(KIND=dp) :: f_ts
199 : REAL(KIND=dp), DIMENSION(3, 3) :: av_ptens, av_ptens_opt
200 17045 : REAL(KIND=dp), DIMENSION(:), POINTER :: cell_gradient, gradient_ts
201 : TYPE(cell_type), POINTER :: cell
202 : TYPE(cp_subsys_type), POINTER :: subsys
203 : TYPE(particle_list_type), POINTER :: core_particles, particles, &
204 : shell_particles
205 : TYPE(spgr_type), POINTER :: spgr
206 : TYPE(virial_type), POINTER :: virial
207 :
208 17045 : NULLIFY (cell)
209 17045 : NULLIFY (core_particles)
210 17045 : NULLIFY (gradient_ts)
211 17045 : NULLIFY (particles)
212 17045 : NULLIFY (shell_particles)
213 17045 : NULLIFY (subsys)
214 17045 : NULLIFY (virial)
215 17045 : NULLIFY (spgr)
216 :
217 17045 : CALL timeset(routineN, handle)
218 :
219 17045 : CALL force_env_get(gopt_env%force_env, subsys=subsys, cell=cell)
220 : CALL cp_subsys_get(subsys, &
221 : core_particles=core_particles, &
222 : particles=particles, &
223 : shell_particles=shell_particles, &
224 17045 : virial=virial)
225 :
226 17045 : spgr => gopt_env%spgr
227 :
228 25450 : SELECT CASE (gopt_env%type_id)
229 : CASE (default_minimization_method_id, default_ts_method_id)
230 8405 : CALL unpack_subsys_particles(subsys=subsys, r=x)
231 8405 : CALL write_structure_data(particles%els, cell, gopt_env%motion_section)
232 15022 : SELECT CASE (gopt_env%type_id)
233 : CASE (default_minimization_method_id)
234 : ! Geometry Minimization
235 : CALL force_env_calc_energy_force(gopt_env%force_env, &
236 : calc_force=PRESENT(gradient), &
237 6617 : require_consistent_energy_force=gopt_env%require_consistent_energy_force)
238 : ! Possibly take the potential energy
239 6617 : IF (PRESENT(f)) THEN
240 6617 : CALL force_env_get(gopt_env%force_env, potential_energy=f)
241 : END IF
242 : ! Possibly take the gradients
243 6617 : IF (PRESENT(gradient)) THEN
244 6079 : IF (master == para_env%mepos) THEN ! we are on the master
245 5927 : CALL pack_subsys_particles(subsys=subsys, f=gradient, fscale=-1.0_dp)
246 5927 : IF (spgr%keep_space_group) THEN
247 8 : CALL spgr_apply_rotations_force(spgr, gradient)
248 8 : CALL unpack_subsys_particles(subsys=subsys, f=gradient, fscale=-1.0_dp)
249 : END IF
250 : END IF
251 : END IF
252 : CASE (default_ts_method_id)
253 : ! Transition State Optimization
254 5364 : ALLOCATE (gradient_ts(particles%n_els*3))
255 : ! Real calculation of energy and forces for transition state optimization:
256 : ! When doing dimer methods forces have to be always computed since the function
257 : ! to minimize is not the energy but the effective force
258 1788 : CALL cp_eval_at_ts(gopt_env, x, f_ts, gradient_ts, calc_force=.TRUE.)
259 1788 : CALL cite_reference(Henkelman1999)
260 : ! Possibly take the potential energy
261 1788 : IF (PRESENT(f)) f = f_ts
262 : ! Possibly take the gradients
263 1788 : IF (PRESENT(gradient)) THEN
264 844 : IF (master == para_env%mepos) THEN ! we are on the master
265 844 : CPASSERT(ASSOCIATED(gradient))
266 29420 : gradient = gradient_ts
267 : END IF
268 : END IF
269 10193 : DEALLOCATE (gradient_ts)
270 : END SELECT
271 : ! This call is necessary for QM/MM if a Translation is applied
272 : ! this makes the geometry optimizer consistent
273 8405 : CALL unpack_subsys_particles(subsys=subsys, r=x)
274 : CASE (default_cell_method_id)
275 : ! Check for VIRIAL
276 8320 : IF (.NOT. virial%pv_availability) THEN
277 : CALL cp_abort(__LOCATION__, &
278 : "For the CELL_OPT task, the FORCE_EVAL/STRESS_TENSOR "// &
279 : "keyword MUST be defined in the input file for the "// &
280 0 : "evaluation of the stress tensor, but none is found!")
281 : END IF
282 8320 : IF (gopt_env%cell_env%keep_volume) THEN
283 2284 : nparticle = force_env_get_nparticle(gopt_env%force_env)
284 2284 : idg = 3*nparticle
285 2284 : CALL rescale_new_cell_volume(cell%deth, x, idg)
286 : END IF
287 :
288 8320 : CALL apply_cell_change(gopt_env, cell, x, update_forces=.FALSE.)
289 : ! Possibly output the new cell used for the next calculation
290 8320 : CALL write_cell(cell, gopt_env%geo_section)
291 : ! Compute the pressure tensor
292 8320 : BLOCK
293 : TYPE(virial_type) :: virial_avg
294 : CALL force_env_calc_energy_force(gopt_env%force_env, &
295 : calc_force=PRESENT(gradient), &
296 8320 : require_consistent_energy_force=gopt_env%require_consistent_energy_force)
297 : ! Possibly take the potential energy
298 8320 : virial_avg = virial
299 8320 : CALL virial_update(virial_avg, subsys, para_env)
300 8320 : IF (PRESENT(f)) THEN
301 8320 : CALL force_env_get(gopt_env%force_env, potential_energy=f)
302 : END IF
303 : ! Possibly take the gradients
304 2063360 : IF (PRESENT(gradient)) THEN
305 6992 : CPASSERT(ANY(virial_avg%pv_total /= 0))
306 : ! Convert the average ptens
307 90896 : av_ptens(:, :) = virial_avg%pv_total(:, :)/cell%deth
308 6992 : IF (master == para_env%mepos) THEN ! we are on the master
309 5333 : CPASSERT(ASSOCIATED(gradient))
310 5333 : nparticle = force_env_get_nparticle(gopt_env%force_env)
311 5333 : nsize = 3*nparticle
312 5333 : CPASSERT((SIZE(gradient) == nsize + 6))
313 5333 : CALL pack_subsys_particles(subsys=subsys, f=gradient(1:nsize), fscale=-1.0_dp)
314 5333 : CALL apply_cell_change(gopt_env, cell, gradient, update_forces=.TRUE.)
315 5333 : IF (spgr%keep_space_group) THEN
316 556 : CALL spgr_apply_rotations_force(spgr, gradient)
317 556 : CALL spgr_apply_rotations_stress(spgr, cell, av_ptens)
318 556 : CALL spgr_write_stress_tensor(av_ptens, spgr)
319 : END IF
320 5333 : cell_gradient => gradient(nsize + 1:nsize + 6)
321 37331 : cell_gradient = 0.0_dp
322 : av_ptens_opt = MATMUL(gopt_env%cell_env%input_to_opt, &
323 421307 : MATMUL(av_ptens, gopt_env%cell_env%opt_to_input))
324 : CALL get_dg_dh(cell_gradient, av_ptens_opt, gopt_env%cell_env%pres_ext, &
325 : gopt_env%cell_env%opt_cell, gopt_env%cell_env%mtrx, &
326 : keep_angles=gopt_env%cell_env%keep_angles, &
327 : keep_symmetry=gopt_env%cell_env%keep_symmetry, &
328 : pres_int=gopt_env%cell_env%pres_int, &
329 : pres_constr=gopt_env%cell_env%pres_constr, &
330 5333 : constraint_id=gopt_env%cell_env%constraint_id)
331 : END IF
332 : ! some callers expect pres_int to be available on all ranks. Also, here master is not necessarily a single rank.
333 : ! Assume at least master==0
334 6992 : CALL para_env%bcast(gopt_env%cell_env%pres_int, 0)
335 6992 : IF (gopt_env%cell_env%constraint_id /= fix_none) THEN
336 296 : CALL para_env%bcast(gopt_env%cell_env%pres_constr, 0)
337 : END IF
338 : END IF
339 : END BLOCK
340 : CASE (default_shellcore_method_id)
341 : idg = 0
342 31040 : DO ip = 1, particles%n_els
343 30720 : shell_index = particles%els(ip)%shell_index
344 31040 : IF (shell_index /= 0) THEN
345 122880 : DO idir = 1, 3
346 92160 : idg = 3*(shell_index - 1) + idir
347 122880 : shell_particles%els(shell_index)%r(idir) = core_particles%els(ip)%r(idir) - x(idg)
348 : END DO
349 : END IF
350 : END DO
351 320 : CALL write_structure_data(particles%els, cell, gopt_env%motion_section)
352 :
353 : ! Shell-core optimization
354 : CALL force_env_calc_energy_force(gopt_env%force_env, &
355 : calc_force=PRESENT(gradient), &
356 320 : require_consistent_energy_force=gopt_env%require_consistent_energy_force)
357 :
358 : ! Possibly take the potential energy
359 320 : IF (PRESENT(f)) THEN
360 320 : CALL force_env_get(gopt_env%force_env, potential_energy=f)
361 : END IF
362 :
363 : ! Possibly take the gradients
364 320 : IF (PRESENT(gradient)) THEN
365 320 : IF (master == para_env%mepos) THEN ! we are on the master
366 320 : CPASSERT(ASSOCIATED(gradient))
367 320 : idg = 0
368 31040 : DO ip = 1, shell_particles%n_els
369 123200 : DO idir = 1, 3
370 92160 : idg = idg + 1
371 122880 : gradient(idg) = -(core_particles%els(ip)%f(idir) - shell_particles%els(ip)%f(idir))
372 : END DO
373 : END DO
374 : END IF
375 : END IF
376 : CASE DEFAULT
377 17045 : CPABORT("Invalid or not yet implemented type of optimization")
378 : END SELECT
379 :
380 17045 : CALL timestop(handle)
381 :
382 17045 : END SUBROUTINE cp_eval_at
383 :
384 : ! **************************************************************************************************
385 : !> \brief Prints iteration step of the optimization procedure on screen
386 : !> \param its ...
387 : !> \param output_unit ...
388 : !> \author Teodoro Laino [tlaino] - University of Zurich - 03.2008
389 : ! **************************************************************************************************
390 9274 : SUBROUTINE gopt_f_ii(its, output_unit)
391 :
392 : INTEGER, INTENT(IN) :: its, output_unit
393 :
394 9274 : IF (output_unit > 0) THEN
395 4796 : WRITE (UNIT=output_unit, FMT="(/,T2,26('-'))")
396 4796 : WRITE (UNIT=output_unit, FMT="(T2,A,I6)") "OPTIMIZATION STEP: ", its
397 4796 : WRITE (UNIT=output_unit, FMT="(T2,26('-'))")
398 4796 : CALL m_flush(output_unit)
399 : END IF
400 :
401 9274 : END SUBROUTINE gopt_f_ii
402 :
403 : ! **************************************************************************************************
404 : !> \brief Retrieves the reporting metadata used during an optimization step.
405 : !> \param gopt_env Optimization environment supplying print configuration and units
406 : !> \param force_env Force environment used for memory sampling
407 : !> \param max_memory Sampled memory, or zero if memory reporting is disabled
408 : !> \param energy_unit Energy reporting unit
409 : !> \param stress_unit Stress reporting unit
410 : ! **************************************************************************************************
411 10435 : SUBROUTINE get_reporting_metadata(gopt_env, force_env, max_memory, energy_unit, stress_unit)
412 :
413 : TYPE(gopt_f_type), POINTER :: gopt_env
414 : TYPE(force_env_type), POINTER :: force_env
415 : INTEGER(KIND=int_8), INTENT(OUT) :: max_memory
416 : CHARACTER(LEN=default_string_length), INTENT(OUT) :: energy_unit, stress_unit
417 :
418 : LOGICAL :: print_memory
419 : TYPE(mp_para_env_type), POINTER :: para_env
420 :
421 10435 : NULLIFY (para_env)
422 10435 : CALL section_vals_val_get(gopt_env%motion_section, "PRINT%MEMORY_INFO", l_val=print_memory)
423 10435 : max_memory = 0
424 10435 : IF (print_memory) THEN
425 10435 : CALL force_env_get(force_env, para_env=para_env)
426 10435 : max_memory = sample_memory(para_env)
427 : END IF
428 :
429 : CALL section_vals_val_get(gopt_env%force_env%force_env_section, &
430 : "PRINT%PROGRAM_RUN_INFO%ENERGY_UNIT", &
431 10435 : c_val=energy_unit)
432 : CALL section_vals_val_get(gopt_env%force_env%force_env_section, &
433 : "PRINT%STRESS_TENSOR%STRESS_UNIT", &
434 10435 : c_val=stress_unit)
435 :
436 10435 : END SUBROUTINE get_reporting_metadata
437 :
438 : ! **************************************************************************************************
439 : !> \brief Handles the Output during an optimization run
440 : !> \param gopt_env ...
441 : !> \param output_unit ...
442 : !> \param opt_energy ...
443 : !> \param wildcard ...
444 : !> \param its ...
445 : !> \param used_time ...
446 : !> \author Teodoro Laino [tlaino] - University of Zurich - 03.2008
447 : ! **************************************************************************************************
448 1163 : SUBROUTINE gopt_f_io_init(gopt_env, output_unit, opt_energy, wildcard, its, used_time)
449 :
450 : TYPE(gopt_f_type), POINTER :: gopt_env
451 : INTEGER, INTENT(IN) :: output_unit
452 : REAL(KIND=dp) :: opt_energy
453 : CHARACTER(LEN=5) :: wildcard
454 : INTEGER, INTENT(IN) :: its
455 : REAL(KIND=dp) :: used_time
456 :
457 : CHARACTER(LEN=default_string_length) :: energy_unit, stress_unit
458 : INTEGER(KIND=int_8) :: max_memory
459 : REAL(KIND=dp) :: pres_int
460 :
461 1163 : CALL get_reporting_metadata(gopt_env, gopt_env%force_env, max_memory, energy_unit, stress_unit)
462 :
463 2130 : SELECT CASE (gopt_env%type_id)
464 : CASE (default_ts_method_id, default_minimization_method_id)
465 : ! Geometry Optimization (Minimization and Transition State Search)
466 967 : IF (.NOT. gopt_env%dimer_rotation) THEN
467 : CALL write_cycle_infos(output_unit, &
468 : it=its, &
469 : etot=opt_energy, &
470 : wildcard=wildcard, &
471 : used_time=used_time, &
472 : max_memory=max_memory, &
473 : energy_unit=energy_unit, &
474 839 : stress_unit=stress_unit)
475 : ELSE
476 : CALL write_rot_cycle_infos(output_unit, &
477 : it=its, &
478 : etot=opt_energy, &
479 : dimer_env=gopt_env%dimer_env, &
480 : wildcard=wildcard, &
481 : used_time=used_time, &
482 128 : max_memory=max_memory)
483 : END IF
484 : CASE (default_cell_method_id)
485 : ! Cell Optimization
486 176 : pres_int = gopt_env%cell_env%pres_int
487 : CALL write_cycle_infos(output_unit, &
488 : it=its, &
489 : etot=opt_energy, &
490 : pres_int=pres_int, &
491 : wildcard=wildcard, &
492 : used_time=used_time, &
493 : max_memory=max_memory, &
494 : energy_unit=energy_unit, &
495 176 : stress_unit=stress_unit)
496 : CASE (default_shellcore_method_id)
497 : CALL write_cycle_infos(output_unit, &
498 : it=its, &
499 : etot=opt_energy, &
500 : wildcard=wildcard, &
501 : used_time=used_time, &
502 : max_memory=max_memory, &
503 : energy_unit=energy_unit, &
504 1163 : stress_unit=stress_unit)
505 : END SELECT
506 :
507 1163 : END SUBROUTINE gopt_f_io_init
508 :
509 : ! **************************************************************************************************
510 : !> \brief Handles the Output during an optimization run
511 : !> \param gopt_env ...
512 : !> \param force_env ...
513 : !> \param root_section ...
514 : !> \param its ...
515 : !> \param opt_energy ...
516 : !> \param output_unit ...
517 : !> \param eold ...
518 : !> \param emin ...
519 : !> \param wildcard ...
520 : !> \param gopt_param ...
521 : !> \param ndf ...
522 : !> \param dx ...
523 : !> \param xi ...
524 : !> \param conv ...
525 : !> \param pred ...
526 : !> \param rat ...
527 : !> \param step ...
528 : !> \param rad ...
529 : !> \param used_time ...
530 : !> \author Teodoro Laino [tlaino] - University of Zurich - 03.2008
531 : ! **************************************************************************************************
532 18544 : SUBROUTINE gopt_f_io(gopt_env, force_env, root_section, its, opt_energy, &
533 9272 : output_unit, eold, emin, wildcard, gopt_param, ndf, dx, xi, conv, pred, rat, &
534 : step, rad, used_time)
535 :
536 : TYPE(gopt_f_type), POINTER :: gopt_env
537 : TYPE(force_env_type), POINTER :: force_env
538 : TYPE(section_vals_type), POINTER :: root_section
539 : INTEGER, INTENT(IN) :: its
540 : REAL(KIND=dp), INTENT(IN) :: opt_energy
541 : INTEGER, INTENT(IN) :: output_unit
542 : REAL(KIND=dp) :: eold, emin
543 : CHARACTER(LEN=5) :: wildcard
544 : TYPE(gopt_param_type), POINTER :: gopt_param
545 : INTEGER, INTENT(IN), OPTIONAL :: ndf
546 : REAL(KIND=dp), DIMENSION(:), INTENT(IN), OPTIONAL :: dx
547 : REAL(KIND=dp), DIMENSION(:), OPTIONAL, POINTER :: xi
548 : LOGICAL, OPTIONAL :: conv
549 : REAL(KIND=dp), INTENT(IN), OPTIONAL :: pred, rat, step, rad
550 : REAL(KIND=dp) :: used_time
551 :
552 : CHARACTER(LEN=default_string_length) :: energy_unit, stress_unit
553 : INTEGER(KIND=int_8) :: max_memory
554 : REAL(KIND=dp) :: pres_diff, pres_diff_constr, pres_int, &
555 : pres_tol
556 :
557 9272 : CALL get_reporting_metadata(gopt_env, force_env, max_memory, energy_unit, stress_unit)
558 :
559 14350 : SELECT CASE (gopt_env%type_id)
560 : CASE (default_ts_method_id, default_minimization_method_id)
561 : ! Geometry Optimization (Minimization and Transition State Search)
562 5078 : IF (.NOT. gopt_env%dimer_rotation) THEN
563 : CALL geo_opt_io(force_env=force_env, root_section=root_section, &
564 4356 : motion_section=gopt_env%motion_section, its=its, opt_energy=opt_energy)
565 : CALL write_cycle_infos(output_unit, &
566 : it=its, &
567 : etot=opt_energy, &
568 : ediff=(opt_energy - eold), &
569 : pred=pred, &
570 : rat=rat, &
571 : step=step, &
572 : rad=rad, &
573 : emin=emin, &
574 : wildcard=wildcard, &
575 : used_time=used_time, &
576 : max_memory=max_memory, &
577 : energy_unit=energy_unit, &
578 4356 : stress_unit=stress_unit)
579 : ! Possibly check convergence
580 4356 : IF (PRESENT(conv)) THEN
581 4356 : CPASSERT(PRESENT(ndf))
582 4356 : CPASSERT(PRESENT(dx))
583 4356 : CPASSERT(PRESENT(xi))
584 : CALL check_and_report_convergence(output_unit, gopt_param, ndf, dx, xi, conv, &
585 4356 : max_memory, stress_unit)
586 : END IF
587 : ELSE
588 722 : CALL update_dimer_vec(gopt_env%dimer_env, gopt_env%motion_section)
589 722 : CALL write_restart(force_env=force_env, root_section=root_section)
590 : CALL write_rot_cycle_infos(output_unit, its, opt_energy, opt_energy - eold, emin, gopt_env%dimer_env, &
591 722 : wildcard=wildcard, used_time=used_time, max_memory=max_memory)
592 : ! Possibly check convergence
593 722 : IF (PRESENT(conv)) THEN
594 722 : CPASSERT(ASSOCIATED(gopt_env%dimer_env))
595 722 : CALL check_rot_conv(gopt_env%dimer_env, output_unit, conv)
596 : END IF
597 : END IF
598 : CASE (default_cell_method_id)
599 : ! Cell Optimization
600 4044 : pres_diff = gopt_env%cell_env%pres_int - gopt_env%cell_env%pres_ext
601 4044 : pres_int = gopt_env%cell_env%pres_int
602 4044 : pres_tol = gopt_env%cell_env%pres_tol
603 : CALL geo_opt_io(force_env=force_env, root_section=root_section, &
604 4044 : motion_section=gopt_env%motion_section, its=its, opt_energy=opt_energy)
605 : CALL write_cycle_infos(output_unit, &
606 : it=its, &
607 : etot=opt_energy, &
608 : ediff=(opt_energy - eold), &
609 : pred=pred, &
610 : rat=rat, &
611 : step=step, &
612 : rad=rad, &
613 : emin=emin, &
614 : pres_int=pres_int, &
615 : wildcard=wildcard, &
616 : used_time=used_time, &
617 : max_memory=max_memory, &
618 : energy_unit=energy_unit, &
619 4044 : stress_unit=stress_unit)
620 : ! Possibly check convergence
621 4044 : IF (PRESENT(conv)) THEN
622 4044 : CPASSERT(PRESENT(ndf))
623 4044 : CPASSERT(PRESENT(dx))
624 4044 : CPASSERT(PRESENT(xi))
625 4044 : IF (gopt_env%cell_env%constraint_id == fix_none) THEN
626 : CALL check_and_report_convergence(output_unit, gopt_param, ndf, dx, xi, conv, &
627 3920 : max_memory, stress_unit, pres_diff, pres_tol)
628 : ELSE
629 124 : pres_diff_constr = gopt_env%cell_env%pres_constr - gopt_env%cell_env%pres_ext
630 : CALL check_and_report_convergence(output_unit, gopt_param, ndf, dx, xi, conv, &
631 : max_memory, stress_unit, pres_diff, pres_tol, &
632 124 : pres_diff_constr)
633 : END IF
634 : END IF
635 : CASE (default_shellcore_method_id)
636 : CALL write_cycle_infos(output_unit, &
637 : it=its, &
638 : etot=opt_energy, &
639 : ediff=(opt_energy - eold), &
640 : pred=pred, &
641 : rat=rat, &
642 : step=step, &
643 : rad=rad, &
644 : emin=emin, &
645 : wildcard=wildcard, &
646 : used_time=used_time, &
647 : max_memory=max_memory, &
648 : energy_unit=energy_unit, &
649 150 : stress_unit=stress_unit)
650 : ! Possibly check convergence
651 9422 : IF (PRESENT(conv)) THEN
652 150 : CPASSERT(PRESENT(ndf))
653 150 : CPASSERT(PRESENT(dx))
654 150 : CPASSERT(PRESENT(xi))
655 : CALL check_and_report_convergence(output_unit, gopt_param, ndf, dx, xi, conv, &
656 150 : max_memory, stress_unit)
657 : END IF
658 : END SELECT
659 :
660 9272 : END SUBROUTINE gopt_f_io
661 :
662 : ! **************************************************************************************************
663 : !> \brief Handles the Output at the end of an optimization run
664 : !> \param gopt_env ...
665 : !> \param force_env ...
666 : !> \param x0 ...
667 : !> \param conv ...
668 : !> \param its ...
669 : !> \param root_section ...
670 : !> \param para_env ...
671 : !> \param master ...
672 : !> \param output_unit ...
673 : !> \author Teodoro Laino [tlaino] - University of Zurich - 03.2008
674 : ! **************************************************************************************************
675 1267 : RECURSIVE SUBROUTINE gopt_f_io_finalize(gopt_env, force_env, x0, conv, its, root_section, &
676 : para_env, master, output_unit)
677 : TYPE(gopt_f_type), POINTER :: gopt_env
678 : TYPE(force_env_type), POINTER :: force_env
679 : REAL(KIND=dp), DIMENSION(:), POINTER :: x0
680 : LOGICAL :: conv
681 : INTEGER :: its
682 : TYPE(section_vals_type), POINTER :: root_section
683 : TYPE(mp_para_env_type), POINTER :: para_env
684 : INTEGER, INTENT(IN) :: master, output_unit
685 :
686 1267 : IF (gopt_env%eval_opt_geo) THEN
687 1247 : IF (.NOT. gopt_env%dimer_rotation) THEN
688 : CALL write_final_info(output_unit, conv, its, gopt_env, x0, master, &
689 1119 : para_env, force_env, gopt_env%motion_section, root_section)
690 : ELSE
691 128 : CALL update_dimer_vec(gopt_env%dimer_env, gopt_env%motion_section)
692 128 : CALL write_restart(force_env=force_env, root_section=root_section)
693 : END IF
694 : END IF
695 :
696 1267 : END SUBROUTINE gopt_f_io_finalize
697 :
698 : ! **************************************************************************************************
699 : !> \brief ...
700 : !> \param output_unit ...
701 : !> \param it ...
702 : !> \param etot ...
703 : !> \param ediff ...
704 : !> \param pred ...
705 : !> \param rat ...
706 : !> \param step ...
707 : !> \param rad ...
708 : !> \param emin ...
709 : !> \param pres_int ...
710 : !> \param wildcard ...
711 : !> \param used_time ...
712 : !> \param max_memory ...
713 : !> \param energy_unit ...
714 : !> \param stress_unit ...
715 : ! **************************************************************************************************
716 9585 : SUBROUTINE write_cycle_infos(output_unit, it, etot, ediff, pred, rat, step, rad, emin, &
717 : pres_int, wildcard, used_time, max_memory, energy_unit, stress_unit)
718 :
719 : INTEGER, INTENT(IN) :: output_unit, it
720 : REAL(KIND=dp), INTENT(IN) :: etot
721 : REAL(KIND=dp), INTENT(IN), OPTIONAL :: ediff, pred, rat, step, rad, emin, &
722 : pres_int
723 : CHARACTER(LEN=5), INTENT(IN) :: wildcard
724 : REAL(KIND=dp), INTENT(IN) :: used_time
725 : INTEGER(KIND=int_8), INTENT(IN) :: max_memory
726 : CHARACTER(LEN=default_string_length), INTENT(IN) :: energy_unit, stress_unit
727 :
728 : CHARACTER(LEN=5) :: tag
729 :
730 9585 : IF (output_unit > 0) THEN
731 4975 : tag = "OPT| "
732 4975 : WRITE (UNIT=output_unit, FMT="(/,T2,A)") tag//REPEAT("*", 74)
733 : WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,I25)") &
734 4975 : tag//"Step number", it
735 : WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,A25)") &
736 4975 : tag//"Optimization method", wildcard
737 : WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,F25.10)") &
738 4975 : tag//"Total energy ["//TRIM(ADJUSTL(energy_unit))//"]", &
739 9950 : cp_unit_from_cp2k(etot, TRIM(energy_unit))
740 4975 : IF (PRESENT(pres_int)) THEN
741 : WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,F25.10)") &
742 2110 : tag//"Internal pressure ["//TRIM(ADJUSTL(stress_unit))//"]", &
743 4220 : cp_unit_from_cp2k(pres_int, TRIM(stress_unit))
744 : END IF
745 4975 : IF (PRESENT(ediff)) THEN
746 : WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,F25.10)") &
747 4434 : tag//"Effective energy change ["//TRIM(ADJUSTL(energy_unit))//"]", &
748 8868 : cp_unit_from_cp2k(ediff, TRIM(energy_unit))
749 : END IF
750 4975 : IF (PRESENT(pred)) THEN
751 : WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,F25.10)") &
752 2094 : tag//"Predicted energy change ["//TRIM(ADJUSTL(energy_unit))//"]", &
753 4188 : cp_unit_from_cp2k(pred, TRIM(energy_unit))
754 : END IF
755 4975 : IF (PRESENT(rat)) THEN
756 : WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,F25.10)") &
757 2350 : tag//"Scaling factor", rat
758 : END IF
759 4975 : IF (PRESENT(step)) THEN
760 : WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,F25.10)") &
761 2350 : tag//"Step size", step
762 : END IF
763 4975 : IF (PRESENT(rad)) THEN
764 : WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,F25.10)") &
765 2350 : tag//"Trust radius", rad
766 : END IF
767 4975 : IF (PRESENT(emin)) THEN
768 4434 : IF (etot < emin) THEN
769 : WRITE (UNIT=output_unit, FMT="(T2,A,T77,A4)") &
770 4026 : tag//"Decrease in energy", " YES"
771 : ELSE
772 : WRITE (UNIT=output_unit, FMT="(T2,A,T77,A4)") &
773 408 : tag//"Decrease in energy", " NO"
774 : END IF
775 : END IF
776 : WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,F25.3)") &
777 4975 : tag//"Used time [s]", used_time
778 4975 : IF (it == 0) THEN
779 535 : WRITE (UNIT=output_unit, FMT="(T2,A)") tag//REPEAT("*", 74)
780 535 : IF (max_memory /= 0) THEN
781 : WRITE (UNIT=output_unit, FMT="(T2,A,T60,1X,I20)") &
782 535 : tag//"Estimated peak process memory [MiB]", &
783 1070 : (max_memory + bytes_per_mib - 1)/bytes_per_mib
784 : END IF
785 : END IF
786 : END IF
787 :
788 9585 : END SUBROUTINE write_cycle_infos
789 :
790 : ! **************************************************************************************************
791 : !> \brief ...
792 : !> \param output_unit ...
793 : !> \param it ...
794 : !> \param etot ...
795 : !> \param ediff ...
796 : !> \param emin ...
797 : !> \param dimer_env ...
798 : !> \param used_time ...
799 : !> \param wildcard ...
800 : !> \param max_memory ...
801 : !> \date 01.2008
802 : !> \author Luca Bellucci and Teodoro Laino - created [tlaino]
803 : ! **************************************************************************************************
804 850 : SUBROUTINE write_rot_cycle_infos(output_unit, it, etot, ediff, emin, dimer_env, used_time, &
805 : wildcard, max_memory)
806 :
807 : INTEGER, INTENT(IN) :: output_unit, it
808 : REAL(KIND=dp), INTENT(IN) :: etot
809 : REAL(KIND=dp), INTENT(IN), OPTIONAL :: ediff, emin
810 : TYPE(dimer_env_type), POINTER :: dimer_env
811 : REAL(KIND=dp), INTENT(IN) :: used_time
812 : CHARACTER(LEN=5), INTENT(IN) :: wildcard
813 : INTEGER(KIND=int_8), INTENT(IN) :: max_memory
814 :
815 : CHARACTER(LEN=5) :: tag
816 :
817 850 : IF (output_unit > 0) THEN
818 425 : tag = "OPT| "
819 425 : WRITE (UNIT=output_unit, FMT="(/,T2,A)") tag//REPEAT("*", 74)
820 : WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,I25)") &
821 425 : tag//"Rotational step number", it
822 : WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,A25)") &
823 425 : tag//"Optimization method", wildcard
824 : WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,F25.10)") &
825 425 : tag//"Local curvature", dimer_env%rot%curvature, &
826 850 : tag//"Total rotational force", etot
827 425 : IF (PRESENT(ediff)) THEN
828 : WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,F25.10)") &
829 361 : tag//"Rotational force change", ediff
830 : END IF
831 425 : IF (PRESENT(emin)) THEN
832 361 : IF (etot < emin) THEN
833 : WRITE (UNIT=output_unit, FMT="(T2,A,T77,A4)") &
834 155 : tag//"Decrease in rotational force", " YES"
835 : ELSE
836 : WRITE (UNIT=output_unit, FMT="(T2,A,T77,A4)") &
837 206 : tag//"Decrease in rotational force", " NO"
838 : END IF
839 : END IF
840 : WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,F25.3)") &
841 425 : tag//"Used time [s]", used_time
842 425 : IF (it == 0) THEN
843 64 : WRITE (UNIT=output_unit, FMT="(T2,A)") tag//REPEAT("*", 74)
844 64 : IF (max_memory /= 0) THEN
845 : WRITE (UNIT=output_unit, FMT="(T2,A,T60,1X,I20)") &
846 64 : tag//"Estimated peak process memory [MiB]", &
847 128 : (max_memory + bytes_per_mib - 1)/bytes_per_mib
848 : END IF
849 : END IF
850 : END IF
851 :
852 850 : END SUBROUTINE write_rot_cycle_infos
853 :
854 : ! **************************************************************************************************
855 : !> \brief Evaluate the geometry/cell optimization convergence criteria (pure decision, no I/O)
856 : !> \param ndf ...
857 : !> \param dr ...
858 : !> \param g ...
859 : !> \param gopt_param ...
860 : !> \param conv ...
861 : !> \param conv_dx ...
862 : !> \param conv_rdx ...
863 : !> \param conv_g ...
864 : !> \param conv_rg ...
865 : !> \param conv_p ...
866 : !> \param max_dr ...
867 : !> \param rms_dr ...
868 : !> \param max_grad ...
869 : !> \param rms_grad ...
870 : !> \param pres_diff ...
871 : !> \param pres_tol ...
872 : !> \param pres_diff_constr ...
873 : ! **************************************************************************************************
874 8550 : SUBROUTINE check_converg(ndf, dr, g, gopt_param, conv, conv_dx, conv_rdx, conv_g, conv_rg, conv_p, &
875 : max_dr, rms_dr, max_grad, rms_grad, pres_diff, pres_tol, pres_diff_constr)
876 :
877 : INTEGER, INTENT(IN) :: ndf
878 : REAL(KIND=dp), INTENT(IN) :: dr(ndf), g(ndf)
879 : TYPE(gopt_param_type), POINTER :: gopt_param
880 : LOGICAL, INTENT(OUT) :: conv, conv_dx, conv_rdx, conv_g, &
881 : conv_rg, conv_p
882 : REAL(KIND=dp), INTENT(OUT) :: max_dr, rms_dr, max_grad, rms_grad
883 : REAL(KIND=dp), INTENT(IN), OPTIONAL :: pres_diff, pres_tol, pres_diff_constr
884 :
885 : INTEGER :: indf
886 : REAL(KIND=dp) :: dumm, dxcon, gcon, rmsgcon, rmsxcon
887 :
888 8550 : dxcon = gopt_param%max_dr
889 8550 : gcon = gopt_param%max_force
890 8550 : rmsgcon = gopt_param%rms_force
891 8550 : rmsxcon = gopt_param%rms_dr
892 :
893 8550 : conv = .FALSE.
894 8550 : conv_dx = .TRUE.
895 8550 : conv_rdx = .TRUE.
896 8550 : conv_g = .TRUE.
897 8550 : conv_rg = .TRUE.
898 8550 : conv_p = .TRUE.
899 :
900 8550 : dumm = 0.0_dp
901 2545146 : DO indf = 1, ndf
902 2536596 : IF (indf == 1) max_dr = ABS(dr(indf))
903 2536596 : dumm = dumm + dr(indf)**2
904 2536596 : IF (ABS(dr(indf)) > dxcon) conv_dx = .FALSE.
905 2545146 : IF (ABS(dr(indf)) > max_dr) max_dr = ABS(dr(indf))
906 : END DO
907 : ! SQRT(dumm/ndf) > rmsxcon
908 8550 : IF (dumm > (rmsxcon*rmsxcon*ndf)) conv_rdx = .FALSE.
909 8550 : rms_dr = SQRT(dumm/ndf)
910 :
911 8550 : dumm = 0.0_dp
912 2545146 : DO indf = 1, ndf
913 2536596 : IF (indf == 1) max_grad = ABS(g(indf))
914 2536596 : dumm = dumm + g(indf)**2
915 2536596 : IF (ABS(g(indf)) > gcon) conv_g = .FALSE.
916 2545146 : IF (ABS(g(indf)) > max_grad) max_grad = ABS(g(indf))
917 : END DO
918 : ! SQRT(dumm/ndf) > rmsgcon
919 8550 : IF (dumm > (rmsgcon*rmsgcon*ndf)) conv_rg = .FALSE.
920 8550 : rms_grad = SQRT(dumm/ndf)
921 :
922 8550 : IF (PRESENT(pres_diff_constr) .AND. PRESENT(pres_tol)) THEN
923 124 : conv_p = ABS(pres_diff_constr) < ABS(pres_tol)
924 8426 : ELSE IF (PRESENT(pres_diff) .AND. PRESENT(pres_tol)) THEN
925 3920 : conv_p = ABS(pres_diff) < ABS(pres_tol)
926 : END IF
927 :
928 8550 : IF (conv_dx .AND. conv_rdx .AND. conv_g .AND. conv_rg .AND. conv_p) conv = .TRUE.
929 :
930 8550 : END SUBROUTINE check_converg
931 :
932 : ! **************************************************************************************************
933 : !> \brief Print one YES/NO convergence flag line
934 : !> \param output_unit ...
935 : !> \param tag ...
936 : !> \param label ...
937 : !> \param flag ...
938 : ! **************************************************************************************************
939 20119 : SUBROUTINE write_conv_flag(output_unit, tag, label, flag)
940 : INTEGER, INTENT(IN) :: output_unit
941 : CHARACTER(LEN=*), INTENT(IN) :: tag, label
942 : LOGICAL, INTENT(IN) :: flag
943 :
944 20119 : IF (flag) THEN
945 3463 : WRITE (UNIT=output_unit, FMT="(T2,A,T77,A4)") tag//label, " YES"
946 : ELSE
947 16656 : WRITE (UNIT=output_unit, FMT="(T2,A,T77,A4)") tag//label, " NO"
948 : END IF
949 20119 : END SUBROUTINE write_conv_flag
950 :
951 : ! **************************************************************************************************
952 : !> \brief Print the per-cycle convergence report (body moved verbatim from check_converg)
953 : !> \param output_unit ...
954 : !> \param gopt_param ...
955 : !> \param conv ...
956 : !> \param conv_dx ...
957 : !> \param conv_rdx ...
958 : !> \param conv_g ...
959 : !> \param conv_rg ...
960 : !> \param conv_p ...
961 : !> \param max_dr ...
962 : !> \param rms_dr ...
963 : !> \param max_grad ...
964 : !> \param rms_grad ...
965 : !> \param max_memory ...
966 : !> \param stress_unit ...
967 : !> \param pres_diff ...
968 : !> \param pres_tol ...
969 : !> \param pres_diff_constr ...
970 : ! **************************************************************************************************
971 8550 : SUBROUTINE write_convergence_infos(output_unit, gopt_param, conv, conv_dx, conv_rdx, conv_g, &
972 : conv_rg, conv_p, max_dr, rms_dr, max_grad, rms_grad, &
973 : max_memory, stress_unit, pres_diff, pres_tol, pres_diff_constr)
974 :
975 : INTEGER, INTENT(IN) :: output_unit
976 : TYPE(gopt_param_type), POINTER :: gopt_param
977 : LOGICAL, INTENT(IN) :: conv, conv_dx, conv_rdx, conv_g, &
978 : conv_rg, conv_p
979 : REAL(KIND=dp), INTENT(IN) :: max_dr, rms_dr, max_grad, rms_grad
980 : INTEGER(KIND=int_8), INTENT(IN) :: max_memory
981 : CHARACTER(LEN=default_string_length), INTENT(IN) :: stress_unit
982 : REAL(KIND=dp), INTENT(IN), OPTIONAL :: pres_diff, pres_tol, pres_diff_constr
983 :
984 : CHARACTER(LEN=5) :: tag
985 : REAL(KIND=dp) :: dxcon, gcon, rmsgcon, rmsxcon
986 :
987 8550 : dxcon = gopt_param%max_dr
988 8550 : gcon = gopt_param%max_force
989 8550 : rmsgcon = gopt_param%rms_force
990 8550 : rmsxcon = gopt_param%rms_dr
991 :
992 8550 : IF (output_unit > 0) THEN
993 :
994 4434 : tag = "OPT| "
995 :
996 4434 : WRITE (UNIT=output_unit, FMT="(T2,A)") TRIM(tag)
997 : WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,F25.10)") &
998 4434 : tag//"Maximum step size", max_dr, &
999 8868 : tag//"Convergence limit for maximum step size", dxcon
1000 : CALL write_conv_flag(output_unit, tag, "Maximum step size is converged", &
1001 4434 : conv_dx)
1002 :
1003 4434 : WRITE (UNIT=output_unit, FMT="(T2,A)") TRIM(tag)
1004 : WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,F25.10)") &
1005 4434 : tag//"RMS step size", rms_dr, &
1006 8868 : tag//"Convergence limit for RMS step size", rmsxcon
1007 : CALL write_conv_flag(output_unit, tag, "RMS step size is converged", &
1008 4434 : conv_rdx)
1009 :
1010 4434 : WRITE (UNIT=output_unit, FMT="(T2,A)") TRIM(tag)
1011 : WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,F25.10)") &
1012 4434 : tag//"Maximum gradient", max_grad, &
1013 8868 : tag//"Convergence limit for maximum gradient", gcon
1014 : CALL write_conv_flag(output_unit, tag, "Maximum gradient is converged", &
1015 4434 : conv_g)
1016 :
1017 4434 : WRITE (UNIT=output_unit, FMT="(T2,A)") TRIM(tag)
1018 : WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,F25.10)") &
1019 4434 : tag//"RMS gradient", rms_grad, &
1020 8868 : tag//"Convergence limit for RMS gradient", rmsgcon
1021 : CALL write_conv_flag(output_unit, tag, "RMS gradient is converged", &
1022 4434 : conv_rg)
1023 :
1024 4434 : IF (PRESENT(pres_diff) .AND. PRESENT(pres_tol)) THEN
1025 2022 : WRITE (UNIT=output_unit, FMT="(T2,A)") TRIM(tag)
1026 2022 : IF (PRESENT(pres_diff_constr)) THEN
1027 : WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,F25.10)") &
1028 : tag//"Pressure deviation without constraint ["// &
1029 62 : TRIM(ADJUSTL(stress_unit))//"]", &
1030 124 : cp_unit_from_cp2k(pres_diff, TRIM(stress_unit))
1031 : WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,F25.10)") &
1032 : tag//"Pressure deviation with constraint ["// &
1033 62 : TRIM(ADJUSTL(stress_unit))//"]", &
1034 124 : cp_unit_from_cp2k(pres_diff_constr, TRIM(stress_unit))
1035 : ELSE
1036 : WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,F25.10)") &
1037 1960 : tag//"Pressure deviation ["//TRIM(ADJUSTL(stress_unit))//"]", &
1038 3920 : cp_unit_from_cp2k(pres_diff, TRIM(stress_unit))
1039 : END IF
1040 : WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,F25.10)") &
1041 2022 : tag//"Pressure tolerance ["//TRIM(ADJUSTL(stress_unit))//"]", &
1042 4044 : cp_unit_from_cp2k(pres_tol, TRIM(stress_unit))
1043 2022 : CALL write_conv_flag(output_unit, tag, "Pressure is converged", conv_p)
1044 : END IF
1045 :
1046 4434 : WRITE (UNIT=output_unit, FMT="(T2,A)") tag//REPEAT("*", 74)
1047 :
1048 4434 : IF (max_memory /= 0) THEN
1049 : WRITE (UNIT=output_unit, FMT="(T2,A,T60,1X,I20)") &
1050 4434 : tag//"Estimated peak process memory after this step [MiB]", &
1051 8868 : (max_memory + bytes_per_mib - 1)/bytes_per_mib
1052 : END IF
1053 :
1054 : END IF
1055 :
1056 8550 : IF ((conv) .AND. (output_unit > 0)) THEN
1057 223 : WRITE (UNIT=output_unit, FMT="(/,T2,A)") REPEAT("*", 79)
1058 : WRITE (UNIT=output_unit, FMT="(T2,A,T25,A,T78,A)") &
1059 223 : "***", "GEOMETRY OPTIMIZATION COMPLETED", "***"
1060 223 : WRITE (UNIT=output_unit, FMT="(T2,A)") REPEAT("*", 79)
1061 : END IF
1062 :
1063 8550 : END SUBROUTINE write_convergence_infos
1064 :
1065 : ! **************************************************************************************************
1066 : !> \brief Check convergence and print the per-cycle report (gopt_f_io call sites)
1067 : !> \param output_unit ...
1068 : !> \param gopt_param ...
1069 : !> \param ndf ...
1070 : !> \param dr ...
1071 : !> \param g ...
1072 : !> \param conv ...
1073 : !> \param max_memory ...
1074 : !> \param stress_unit ...
1075 : !> \param pres_diff ...
1076 : !> \param pres_tol ...
1077 : !> \param pres_diff_constr ...
1078 : ! **************************************************************************************************
1079 8550 : SUBROUTINE check_and_report_convergence(output_unit, gopt_param, ndf, dr, g, conv, &
1080 : max_memory, stress_unit, pres_diff, pres_tol, pres_diff_constr)
1081 :
1082 : INTEGER, INTENT(IN) :: output_unit
1083 : TYPE(gopt_param_type), POINTER :: gopt_param
1084 : INTEGER, INTENT(IN) :: ndf
1085 : REAL(KIND=dp), INTENT(IN) :: dr(ndf), g(ndf)
1086 : LOGICAL, INTENT(INOUT) :: conv
1087 : INTEGER(KIND=int_8), INTENT(IN) :: max_memory
1088 : CHARACTER(LEN=default_string_length), INTENT(IN) :: stress_unit
1089 : REAL(KIND=dp), INTENT(IN), OPTIONAL :: pres_diff, pres_tol, pres_diff_constr
1090 :
1091 : LOGICAL :: conv_dx, conv_g, conv_p, conv_rdx, &
1092 : conv_rg
1093 : REAL(KIND=dp) :: max_dr, max_grad, rms_dr, rms_grad
1094 :
1095 : CALL check_converg(ndf, dr, g, gopt_param, conv, conv_dx, conv_rdx, conv_g, conv_rg, &
1096 : conv_p, max_dr, rms_dr, max_grad, rms_grad, pres_diff, pres_tol, &
1097 8550 : pres_diff_constr)
1098 : CALL write_convergence_infos(output_unit, gopt_param, conv, conv_dx, conv_rdx, conv_g, &
1099 : conv_rg, conv_p, max_dr, rms_dr, max_grad, rms_grad, &
1100 8550 : max_memory, stress_unit, pres_diff, pres_tol, pres_diff_constr)
1101 8550 : END SUBROUTINE check_and_report_convergence
1102 :
1103 : ! **************************************************************************************************
1104 : !> \brief ...
1105 : !> \param dimer_env ...
1106 : !> \param output_unit ...
1107 : !> \param conv ...
1108 : !> \date 01.2008
1109 : !> \author Luca Bellucci and Teodoro Laino - created [tlaino]
1110 : ! **************************************************************************************************
1111 722 : SUBROUTINE check_rot_conv(dimer_env, output_unit, conv)
1112 :
1113 : TYPE(dimer_env_type), POINTER :: dimer_env
1114 : INTEGER, INTENT(IN) :: output_unit
1115 : LOGICAL, INTENT(OUT) :: conv
1116 :
1117 : CHARACTER(LEN=5) :: tag
1118 :
1119 722 : conv = (ABS(dimer_env%rot%angle2) < dimer_env%rot%angle_tol)
1120 :
1121 722 : IF (output_unit > 0) THEN
1122 361 : tag = "OPT| "
1123 361 : WRITE (UNIT=output_unit, FMT="(T2,A)") TRIM(tag)
1124 : WRITE (UNIT=output_unit, FMT="(T2,A,T55,1X,F25.10)") &
1125 361 : tag//"Predicted angle step size", dimer_env%rot%angle1, &
1126 361 : tag//"Effective angle step size", dimer_env%rot%angle2, &
1127 722 : tag//"Convergence limit for angle step size", dimer_env%rot%angle_tol
1128 361 : CALL write_conv_flag(output_unit, tag, "Angle step size is converged", conv)
1129 361 : WRITE (UNIT=output_unit, FMT="(T2,A)") tag//REPEAT("*", 74)
1130 : END IF
1131 :
1132 722 : IF ((conv) .AND. (output_unit > 0)) THEN
1133 59 : WRITE (UNIT=output_unit, FMT="(/,T2,A)") REPEAT("*", 79)
1134 : WRITE (UNIT=output_unit, FMT="(T2,A,T25,A,T78,A)") &
1135 59 : "***", "ROTATION OPTIMIZATION COMPLETED", "***"
1136 59 : WRITE (UNIT=output_unit, FMT="(T2,A)") REPEAT("*", 79)
1137 : END IF
1138 :
1139 722 : END SUBROUTINE check_rot_conv
1140 :
1141 : ! **************************************************************************************************
1142 : !> \brief ...
1143 : !> \param output_unit ...
1144 : !> \param conv ...
1145 : !> \param it ...
1146 : !> \param gopt_env ...
1147 : !> \param x0 ...
1148 : !> \param master ...
1149 : !> \param para_env ...
1150 : !> \param force_env ...
1151 : !> \param motion_section ...
1152 : !> \param root_section ...
1153 : !> \date 11.2007
1154 : !> \author Teodoro Laino [tlaino] - University of Zurich
1155 : ! **************************************************************************************************
1156 1119 : RECURSIVE SUBROUTINE write_final_info(output_unit, conv, it, gopt_env, x0, master, para_env, force_env, &
1157 : motion_section, root_section)
1158 : INTEGER, INTENT(IN) :: output_unit
1159 : LOGICAL, INTENT(IN) :: conv
1160 : INTEGER, INTENT(INOUT) :: it
1161 : TYPE(gopt_f_type), POINTER :: gopt_env
1162 : REAL(KIND=dp), DIMENSION(:), POINTER :: x0
1163 : INTEGER, INTENT(IN) :: master
1164 : TYPE(mp_para_env_type), POINTER :: para_env
1165 : TYPE(force_env_type), POINTER :: force_env
1166 : TYPE(section_vals_type), POINTER :: motion_section, root_section
1167 :
1168 : CHARACTER(LEN=default_string_length) :: constraint_label
1169 : LOGICAL :: keep_angles, keep_symmetry, keep_volume
1170 : REAL(KIND=dp) :: etot
1171 : TYPE(cell_type), POINTER :: cell
1172 : TYPE(cp_subsys_type), POINTER :: subsys
1173 : TYPE(particle_list_type), POINTER :: particles
1174 1119 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
1175 :
1176 1119 : CALL force_env_get(force_env, cell=cell, subsys=subsys)
1177 1119 : CALL cp_subsys_get(subsys=subsys, particles=particles)
1178 1119 : particle_set => particles%els
1179 :
1180 : ! Passing gopt_f_type pointer gopt_env to particle_methods where
1181 : ! write_final_structure is defined causes a circular dependency, so it
1182 : ! is necessary to get some flags by preprocessing...
1183 1119 : keep_angles = .TRUE.
1184 1119 : keep_symmetry = .TRUE.
1185 1119 : keep_volume = .TRUE.
1186 1119 : constraint_label = "NONE"
1187 1119 : IF (gopt_env%type_id == default_cell_method_id) THEN
1188 234 : keep_angles = gopt_env%cell_env%keep_angles
1189 234 : keep_symmetry = gopt_env%cell_env%keep_symmetry
1190 234 : keep_volume = gopt_env%cell_env%keep_volume
1191 234 : constraint_label = cell_opt_constraint_label(gopt_env%cell_env%constraint_id)
1192 : END IF
1193 : CALL write_final_structure(particle_set, cell, motion_section, conv, &
1194 : keep_angles, keep_symmetry, keep_volume, &
1195 1119 : gopt_env%label, constraint_label)
1196 :
1197 1119 : IF (conv) THEN
1198 382 : it = it + 1
1199 382 : CALL write_structure_data(particle_set, cell, motion_section)
1200 382 : CALL write_restart(force_env=force_env, root_section=root_section)
1201 :
1202 382 : IF (output_unit > 0) THEN
1203 214 : WRITE (UNIT=output_unit, FMT="(/,T20,' Reevaluating energy at the minimum')")
1204 : END IF
1205 :
1206 : CALL cp_eval_at(gopt_env, x0, f=etot, master=master, &
1207 382 : para_env=para_env)
1208 382 : CALL write_geo_traj(force_env, root_section, it, etot)
1209 382 : CALL write_simulation_cell(cell, motion_section, it, 0.0_dp)
1210 : END IF
1211 :
1212 1119 : END SUBROUTINE write_final_info
1213 :
1214 : ! **************************************************************************************************
1215 : !> \brief Specific driver for dumping trajectory during a GEO_OPT
1216 : !> \param force_env ...
1217 : !> \param root_section ...
1218 : !> \param it ...
1219 : !> \param etot ...
1220 : !> \date 11.2007
1221 : !> \par History
1222 : !> 09.2010: Output of core and shell positions and forces (MK)
1223 : !> \author Teodoro Laino [tlaino] - University of Zurich
1224 : ! **************************************************************************************************
1225 17564 : SUBROUTINE write_geo_traj(force_env, root_section, it, etot)
1226 :
1227 : TYPE(force_env_type), POINTER :: force_env
1228 : TYPE(section_vals_type), POINTER :: root_section
1229 : INTEGER, INTENT(IN) :: it
1230 : REAL(KIND=dp), INTENT(IN) :: etot
1231 :
1232 : LOGICAL :: shell_adiabatic, shell_present
1233 : TYPE(atomic_kind_list_type), POINTER :: atomic_kinds
1234 8782 : TYPE(atomic_kind_type), DIMENSION(:), POINTER :: atomic_kind_set
1235 : TYPE(cp_subsys_type), POINTER :: subsys
1236 : TYPE(particle_list_type), POINTER :: core_particles, shell_particles
1237 :
1238 8782 : NULLIFY (atomic_kinds)
1239 8782 : NULLIFY (atomic_kind_set)
1240 8782 : NULLIFY (core_particles)
1241 8782 : NULLIFY (shell_particles)
1242 8782 : NULLIFY (subsys)
1243 :
1244 8782 : CALL write_trajectory(force_env, root_section, it, 0.0_dp, 0.0_dp, etot)
1245 : ! Print Force
1246 8782 : CALL write_trajectory(force_env, root_section, it, 0.0_dp, 0.0_dp, etot, "FORCES", middle_name="frc")
1247 8782 : CALL force_env_get(force_env, subsys=subsys)
1248 8782 : CALL cp_subsys_get(subsys, atomic_kinds=atomic_kinds)
1249 8782 : atomic_kind_set => atomic_kinds%els
1250 : CALL get_atomic_kind_set(atomic_kind_set, &
1251 : shell_present=shell_present, &
1252 8782 : shell_adiabatic=shell_adiabatic)
1253 8782 : IF (shell_present) THEN
1254 : CALL cp_subsys_get(subsys, &
1255 : core_particles=core_particles, &
1256 3414 : shell_particles=shell_particles)
1257 : CALL write_trajectory(force_env, root_section, it=it, time=0.0_dp, dtime=0.0_dp, &
1258 : etot=etot, pk_name="SHELL_TRAJECTORY", middle_name="shpos", &
1259 3414 : particles=shell_particles)
1260 3414 : IF (shell_adiabatic) THEN
1261 : CALL write_trajectory(force_env, root_section, it=it, time=0.0_dp, dtime=0.0_dp, &
1262 : etot=etot, pk_name="SHELL_FORCES", middle_name="shfrc", &
1263 3414 : particles=shell_particles)
1264 : CALL write_trajectory(force_env, root_section, it=it, time=0.0_dp, dtime=0.0_dp, &
1265 : etot=etot, pk_name="CORE_TRAJECTORY", middle_name="copos", &
1266 3414 : particles=core_particles)
1267 : CALL write_trajectory(force_env, root_section, it=it, time=0.0_dp, dtime=0.0_dp, &
1268 : etot=etot, pk_name="CORE_FORCES", middle_name="cofrc", &
1269 3414 : particles=core_particles)
1270 : END IF
1271 : END IF
1272 :
1273 8782 : END SUBROUTINE write_geo_traj
1274 :
1275 : ! **************************************************************************************************
1276 : !> \brief ...
1277 : !> \param gopt_env ...
1278 : !> \param output_unit ...
1279 : !> \param label ...
1280 : !> \date 01.2008
1281 : !> \author Teodoro Laino [tlaino] - University of Zurich
1282 : ! **************************************************************************************************
1283 1267 : SUBROUTINE print_geo_opt_header(gopt_env, output_unit, label)
1284 :
1285 : TYPE(gopt_f_type), POINTER :: gopt_env
1286 : INTEGER, INTENT(IN) :: output_unit
1287 : CHARACTER(LEN=*), INTENT(IN) :: label
1288 :
1289 : CHARACTER(LEN=default_string_length) :: my_format, my_label
1290 : INTEGER :: ix
1291 :
1292 1267 : IF (output_unit > 0) THEN
1293 657 : WRITE (UNIT=output_unit, FMT="(/,T2,A)") REPEAT("*", 79)
1294 657 : IF (gopt_env%dimer_rotation) THEN
1295 64 : my_label = "OPTIMIZING DIMER ROTATION"
1296 : ELSE
1297 593 : my_label = "STARTING "//gopt_env%tag(1:8)//" OPTIMIZATION"
1298 : END IF
1299 :
1300 657 : ix = (80 - 7 - LEN_TRIM(my_label))/2
1301 657 : ix = ix + 5
1302 657 : my_format = "(T2,A,T"//cp_to_string(ix)//",A,T78,A)"
1303 657 : WRITE (UNIT=output_unit, FMT=TRIM(my_format)) "***", TRIM(my_label), "***"
1304 :
1305 657 : ix = (80 - 7 - LEN_TRIM(label))/2
1306 657 : ix = ix + 5
1307 657 : my_format = "(T2,A,T"//cp_to_string(ix)//",A,T78,A)"
1308 657 : WRITE (UNIT=output_unit, FMT=TRIM(my_format)) "***", TRIM(label), "***"
1309 :
1310 657 : WRITE (UNIT=output_unit, FMT="(T2,A)") REPEAT("*", 79)
1311 657 : CALL m_flush(output_unit)
1312 : END IF
1313 1267 : END SUBROUTINE print_geo_opt_header
1314 :
1315 : ! **************************************************************************************************
1316 : !> \brief ...
1317 : !> \param gopt_env ...
1318 : !> \param output_unit ...
1319 : !> \date 01.2008
1320 : !> \author Teodoro Laino [tlaino] - University of Zurich
1321 : ! **************************************************************************************************
1322 735 : SUBROUTINE print_geo_opt_nc(gopt_env, output_unit)
1323 :
1324 : TYPE(gopt_f_type), POINTER :: gopt_env
1325 : INTEGER, INTENT(IN) :: output_unit
1326 :
1327 735 : IF (output_unit > 0) THEN
1328 : WRITE (UNIT=output_unit, FMT="(/,T2,A)") &
1329 368 : "*** MAXIMUM NUMBER OF OPTIMIZATION STEPS REACHED ***"
1330 368 : IF (.NOT. gopt_env%dimer_rotation) THEN
1331 : WRITE (UNIT=output_unit, FMT="(T2,A)") &
1332 363 : "*** EXITING GEOMETRY OPTIMIZATION ***"
1333 : ELSE
1334 : WRITE (UNIT=output_unit, FMT="(T2,A)") &
1335 5 : "*** EXITING ROTATION OPTIMIZATION ***"
1336 : END IF
1337 368 : CALL m_flush(output_unit)
1338 : END IF
1339 :
1340 735 : END SUBROUTINE print_geo_opt_nc
1341 :
1342 : ! **************************************************************************************************
1343 : !> \brief Prints information during GEO_OPT common to all optimizers
1344 : !> \param force_env ...
1345 : !> \param root_section ...
1346 : !> \param motion_section ...
1347 : !> \param its ...
1348 : !> \param opt_energy ...
1349 : !> \date 02.2008
1350 : !> \author Teodoro Laino [tlaino] - University of Zurich
1351 : !> \version 1.0
1352 : ! **************************************************************************************************
1353 8400 : SUBROUTINE geo_opt_io(force_env, root_section, motion_section, its, opt_energy)
1354 :
1355 : TYPE(force_env_type), POINTER :: force_env
1356 : TYPE(section_vals_type), POINTER :: root_section, motion_section
1357 : INTEGER, INTENT(IN) :: its
1358 : REAL(KIND=dp), INTENT(IN) :: opt_energy
1359 :
1360 : TYPE(atomic_kind_list_type), POINTER :: atomic_kinds
1361 8400 : TYPE(atomic_kind_type), DIMENSION(:), POINTER :: atomic_kind_set
1362 : TYPE(cell_type), POINTER :: cell
1363 : TYPE(cp_subsys_type), POINTER :: subsys
1364 : TYPE(distribution_1d_type), POINTER :: local_particles
1365 : TYPE(mp_para_env_type), POINTER :: para_env
1366 : TYPE(particle_list_type), POINTER :: particles
1367 8400 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
1368 : TYPE(virial_type), POINTER :: virial
1369 :
1370 8400 : NULLIFY (para_env, atomic_kind_set, subsys, particle_set, &
1371 8400 : local_particles, atomic_kinds, particles)
1372 :
1373 : ! Write Restart File
1374 8400 : CALL write_restart(force_env=force_env, root_section=root_section)
1375 :
1376 : ! Write Trajectory
1377 8400 : CALL write_geo_traj(force_env, root_section, its, opt_energy)
1378 :
1379 : ! Write the stress Tensor
1380 : CALL force_env_get(force_env, cell=cell, para_env=para_env, &
1381 8400 : subsys=subsys)
1382 : CALL cp_subsys_get(subsys=subsys, atomic_kinds=atomic_kinds, local_particles=local_particles, &
1383 8400 : particles=particles, virial=virial)
1384 8400 : atomic_kind_set => atomic_kinds%els
1385 8400 : particle_set => particles%els
1386 : CALL virial_evaluate(atomic_kind_set, particle_set, local_particles, &
1387 8400 : virial, para_env)
1388 8400 : CALL write_stress_tensor_to_file(virial, cell, motion_section, its, 0.0_dp)
1389 :
1390 : ! Write the cell
1391 8400 : CALL write_simulation_cell(cell, motion_section, its, 0.0_dp)
1392 :
1393 8400 : END SUBROUTINE geo_opt_io
1394 :
1395 : ! **************************************************************************************************
1396 : !> \brief Apply coordinate transformations after cell (shape) change
1397 : !> \param gopt_env ...
1398 : !> \param cell ...
1399 : !> \param x ...
1400 : !> \param update_forces ...
1401 : !> \date 05.11.2012 (revised version of unbiase_coordinates moved here, MK)
1402 : !> \author Matthias Krack
1403 : !> \version 1.0
1404 : ! **************************************************************************************************
1405 13653 : SUBROUTINE apply_cell_change(gopt_env, cell, x, update_forces)
1406 :
1407 : TYPE(gopt_f_type), POINTER :: gopt_env
1408 : TYPE(cell_type), POINTER :: cell
1409 : REAL(KIND=dp), DIMENSION(:), POINTER :: x
1410 : LOGICAL, INTENT(IN) :: update_forces
1411 :
1412 : INTEGER :: i, iatom, idg, j, natom, nparticle, &
1413 : shell_index
1414 : REAL(KIND=dp) :: fc, fs, mass
1415 : REAL(KIND=dp), DIMENSION(3) :: s
1416 : TYPE(cell_type), POINTER :: cell_ref
1417 : TYPE(cp_subsys_type), POINTER :: subsys
1418 : TYPE(particle_list_type), POINTER :: core_particles, particles, &
1419 : shell_particles
1420 :
1421 13653 : NULLIFY (cell_ref)
1422 13653 : NULLIFY (core_particles)
1423 13653 : NULLIFY (particles)
1424 13653 : NULLIFY (shell_particles)
1425 13653 : NULLIFY (subsys)
1426 :
1427 13653 : natom = force_env_get_natom(gopt_env%force_env)
1428 13653 : nparticle = force_env_get_nparticle(gopt_env%force_env)
1429 : CALL force_env_get(gopt_env%force_env, &
1430 13653 : subsys=subsys)
1431 : CALL cp_subsys_get(subsys=subsys, &
1432 : core_particles=core_particles, &
1433 : particles=particles, &
1434 13653 : shell_particles=shell_particles)
1435 :
1436 : ! Retrieve the reference cell
1437 13653 : CALL cell_create(cell_ref)
1438 13653 : CALL cell_copy(cell, cell_ref, tag="CELL_OPT_REF")
1439 :
1440 : ! Load the updated cell information
1441 13653 : idg = 3*nparticle
1442 13653 : CALL init_cell(cell_ref, hmat=gopt_env%h_ref)
1443 13653 : CPASSERT((SIZE(x) == idg + 6))
1444 :
1445 13653 : IF (update_forces) THEN
1446 :
1447 : ! Transform particle forces back to reference cell
1448 : idg = 1
1449 339687 : DO iatom = 1, natom
1450 334354 : CALL real_to_scaled(s, x(idg:idg + 2), cell)
1451 334354 : CALL scaled_to_real(x(idg:idg + 2), s, cell_ref)
1452 339687 : idg = idg + 3
1453 : END DO
1454 :
1455 : ELSE
1456 :
1457 : ! Update the six independent components in the canonical optimization frame.
1458 108160 : gopt_env%cell_env%opt_cell%hmat = 0.0_dp
1459 33280 : DO i = 1, 3
1460 83200 : DO j = 1, i
1461 49920 : idg = idg + 1
1462 74880 : gopt_env%cell_env%opt_cell%hmat(j, i) = x(idg)
1463 : END DO
1464 : END DO
1465 8320 : CALL init_cell(gopt_env%cell_env%opt_cell)
1466 8320 : IF (gopt_env%spgr%keep_space_group) THEN
1467 798 : CALL spgr_project_cell_metric(gopt_env%spgr, gopt_env%cell_env%opt_cell)
1468 : ! Keep the optimizer variables synchronized with the projected cell.
1469 798 : idg = 3*nparticle
1470 3192 : DO i = 1, 3
1471 7980 : DO j = 1, i
1472 4788 : idg = idg + 1
1473 7182 : x(idg) = gopt_env%cell_env%opt_cell%hmat(j, i)
1474 : END DO
1475 : END DO
1476 : END IF
1477 :
1478 : ! Reconstruct the physical cell in the fixed orientation of the input cell.
1479 : cell%hmat = MATMUL(gopt_env%cell_env%opt_to_input, &
1480 648960 : gopt_env%cell_env%opt_cell%hmat)
1481 8320 : CALL init_cell(cell)
1482 8320 : CALL cp_subsys_set(subsys, cell=cell)
1483 :
1484 : ! Retrieve particle coordinates for the current cell
1485 8320 : idg = 1
1486 635672 : DO iatom = 1, natom
1487 627352 : CALL real_to_scaled(s, x(idg:idg + 2), cell_ref)
1488 627352 : shell_index = particles%els(iatom)%shell_index
1489 627352 : IF (shell_index == 0) THEN
1490 307612 : CALL scaled_to_real(particles%els(iatom)%r, s, cell)
1491 : ELSE
1492 319740 : CALL scaled_to_real(core_particles%els(shell_index)%r, s, cell)
1493 319740 : i = 3*(natom + shell_index - 1) + 1
1494 319740 : CALL real_to_scaled(s, x(i:i + 2), cell_ref)
1495 319740 : CALL scaled_to_real(shell_particles%els(shell_index)%r, s, cell)
1496 : ! Update atomic position due to core and shell motion
1497 319740 : mass = particles%els(iatom)%atomic_kind%mass
1498 319740 : fc = core_particles%els(shell_index)%atomic_kind%shell%mass_core/mass
1499 319740 : fs = shell_particles%els(shell_index)%atomic_kind%shell%mass_shell/mass
1500 : particles%els(iatom)%r(1:3) = fc*core_particles%els(shell_index)%r(1:3) + &
1501 2557920 : fs*shell_particles%els(shell_index)%r(1:3)
1502 : END IF
1503 635672 : idg = idg + 3
1504 : END DO
1505 : END IF
1506 :
1507 13653 : CALL cell_release(cell_ref)
1508 :
1509 13653 : END SUBROUTINE apply_cell_change
1510 :
1511 : ! **************************************************************************************************
1512 : !> \brief Identify the space group, symmetrize x0 and print it (KEEP_SPACE_GROUP)
1513 : !> \param gopt_env ...
1514 : !> \param x0 ...
1515 : !> \param geo_section ...
1516 : !> \param output_unit ...
1517 : ! **************************************************************************************************
1518 1267 : SUBROUTINE gopt_f_space_group_init(gopt_env, x0, geo_section, output_unit)
1519 : TYPE(gopt_f_type), POINTER :: gopt_env
1520 : REAL(KIND=dp), DIMENSION(:), INTENT(INOUT) :: x0
1521 : TYPE(section_vals_type), POINTER :: geo_section
1522 : INTEGER, INTENT(IN) :: output_unit
1523 :
1524 : TYPE(cp_subsys_type), POINTER :: subsys
1525 :
1526 1267 : NULLIFY (subsys)
1527 :
1528 1267 : IF (.NOT. gopt_env%spgr%keep_space_group) RETURN
1529 36 : SELECT CASE (gopt_env%type_id)
1530 : CASE (default_minimization_method_id, default_ts_method_id, default_cell_method_id)
1531 18 : CALL force_env_get(gopt_env%force_env, subsys=subsys)
1532 18 : CALL identify_space_group(subsys, geo_section, gopt_env, output_unit)
1533 18 : CALL spgr_apply_rotations_coord(gopt_env%spgr, x0)
1534 18 : CALL print_spgr(gopt_env%spgr)
1535 : CASE DEFAULT
1536 18 : gopt_env%spgr%keep_space_group = .FALSE.
1537 : END SELECT
1538 : END SUBROUTINE gopt_f_space_group_init
1539 :
1540 : ! **************************************************************************************************
1541 : !> \brief Identify and print the space group of the current structure (SHOW_SPACE_GROUP)
1542 : !> \param gopt_env ...
1543 : !> \param geo_section ...
1544 : !> \param output_unit ...
1545 : ! **************************************************************************************************
1546 1267 : SUBROUTINE gopt_f_space_group_show(gopt_env, geo_section, output_unit)
1547 : TYPE(gopt_f_type), POINTER :: gopt_env
1548 : TYPE(section_vals_type), POINTER :: geo_section
1549 : INTEGER, INTENT(IN) :: output_unit
1550 :
1551 : TYPE(cp_subsys_type), POINTER :: subsys
1552 :
1553 1267 : NULLIFY (subsys)
1554 :
1555 1267 : IF (.NOT. gopt_env%spgr%show_space_group) RETURN
1556 6 : CALL force_env_get(gopt_env%force_env, subsys=subsys)
1557 6 : CALL identify_space_group(subsys, geo_section, gopt_env, output_unit)
1558 6 : CALL print_spgr(gopt_env%spgr)
1559 : END SUBROUTINE gopt_f_space_group_show
1560 :
1561 : ! **************************************************************************************************
1562 : !> \brief Project optimizer coordinates onto the space-group-invariant subspace
1563 : !> (KEEP_SPACE_GROUP)
1564 : !> \param gopt_env ...
1565 : !> \param x ...
1566 : ! **************************************************************************************************
1567 28497 : SUBROUTINE gopt_f_project_coord(gopt_env, x)
1568 : TYPE(gopt_f_type), POINTER :: gopt_env
1569 : REAL(KIND=dp), DIMENSION(:), INTENT(INOUT) :: x
1570 :
1571 28497 : IF (gopt_env%spgr%keep_space_group) CALL spgr_apply_rotations_coord(gopt_env%spgr, x)
1572 28497 : END SUBROUTINE gopt_f_project_coord
1573 :
1574 : ! **************************************************************************************************
1575 : !> \brief Project a gradient, displacement or search direction (linear, no
1576 : !> translations)
1577 : !> \param gopt_env ...
1578 : !> \param v ...
1579 : ! **************************************************************************************************
1580 41433 : SUBROUTINE gopt_f_project_vector(gopt_env, v)
1581 : TYPE(gopt_f_type), POINTER :: gopt_env
1582 : REAL(KIND=dp), DIMENSION(:), INTENT(INOUT) :: v
1583 :
1584 41433 : IF (gopt_env%spgr%keep_space_group) CALL spgr_apply_rotations_force(gopt_env%spgr, v)
1585 41433 : END SUBROUTINE gopt_f_project_vector
1586 :
1587 : ! **************************************************************************************************
1588 : !> \brief Restrict a proposed optimizer step: cell constraints (CELL_OPT),
1589 : !> then space group
1590 : !> \param gopt_env ...
1591 : !> \param dr ...
1592 : ! **************************************************************************************************
1593 4382 : SUBROUTINE gopt_f_project_step(gopt_env, dr)
1594 : TYPE(gopt_f_type), POINTER :: gopt_env
1595 : REAL(KIND=dp), DIMENSION(:), INTENT(INOUT), TARGET :: dr
1596 :
1597 4382 : REAL(KIND=dp), DIMENSION(:), POINTER :: cell_step
1598 :
1599 4382 : IF (gopt_env%type_id == default_cell_method_id) THEN
1600 604 : cell_step => dr(SIZE(dr) - 5:SIZE(dr))
1601 : CALL apply_cell_constraints(cell_step, gopt_env%cell_env%opt_cell, &
1602 : gopt_env%cell_env%keep_angles, gopt_env%cell_env%keep_symmetry, &
1603 604 : gopt_env%cell_env%constraint_id)
1604 : END IF
1605 4382 : CALL gopt_f_project_vector(gopt_env, dr)
1606 4382 : END SUBROUTINE gopt_f_project_step
1607 :
1608 : END MODULE gopt_f_methods
|