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 : MODULE optimize_basis
8 : USE cp_blacs_env, ONLY: cp_blacs_env_type
9 : USE cp_dbcsr_api, ONLY: dbcsr_p_type
10 : USE cp_dbcsr_operations, ONLY: dbcsr_deallocate_matrix_set
11 : USE cp_fm_struct, ONLY: cp_fm_struct_create,&
12 : cp_fm_struct_release,&
13 : cp_fm_struct_type
14 : USE cp_fm_types, ONLY: cp_fm_release,&
15 : cp_fm_type
16 : USE cp_log_handling, ONLY: cp_get_default_logger,&
17 : cp_logger_get_default_unit_nr,&
18 : cp_logger_type
19 : USE cp_output_handling, ONLY: silent_print_level
20 : USE f77_interface, ONLY: create_force_env,&
21 : destroy_force_env,&
22 : f_env_add_defaults,&
23 : f_env_get_from_id,&
24 : f_env_rm_defaults,&
25 : f_env_type
26 : USE force_env_types, ONLY: force_env_get,&
27 : force_env_type
28 : USE global_types, ONLY: global_environment_type
29 : USE input_constants, ONLY: restart_guess
30 : USE input_cp2k_check, ONLY: check_cp2k_input
31 : USE input_cp2k_read, ONLY: empty_initial_variables,&
32 : read_input
33 : USE input_section_types, ONLY: section_type,&
34 : section_vals_duplicate,&
35 : section_vals_get,&
36 : section_vals_get_subs_vals,&
37 : section_vals_release,&
38 : section_vals_type,&
39 : section_vals_val_get,&
40 : section_vals_val_set
41 : USE kinds, ONLY: default_path_length,&
42 : default_string_length,&
43 : dp
44 : USE machine, ONLY: m_chdir,&
45 : m_getcwd,&
46 : m_walltime
47 : USE message_passing, ONLY: mp_comm_type,&
48 : mp_para_env_release,&
49 : mp_para_env_type
50 : USE optbas_fenv_manipulation, ONLY: allocate_mo_sets,&
51 : calculate_ks_matrix,&
52 : calculate_overlap_inverse,&
53 : modify_input_settings,&
54 : update_basis_set
55 : USE optbas_frontier_orbital_screening,ONLY: run_frontier_orbital_screening
56 : USE optbas_frontier_orbitals_utils, ONLY: evaluate_frontier_orbitals_objective,&
57 : frontier_orbitals_reference_init,&
58 : frontier_orbitals_reference_release,&
59 : frontier_orbitals_reference_type,&
60 : frontier_orbitals_result_type,&
61 : print_frontier_orbital_basis_sets
62 : USE optbas_opt_utils, ONLY: evaluate_optvals,&
63 : fit_mo_coeffs,&
64 : optbas_build_neighborlist
65 : USE optimize_basis_types, ONLY: basis_optimization_type,&
66 : deallocate_basis_optimization_type,&
67 : method_mo_fit_occ,&
68 : method_mo_fit_occ_virtual,&
69 : subset_type
70 : USE optimize_basis_utils, ONLY: get_set_and_basis_id,&
71 : optimize_basis_init_read_input,&
72 : update_derived_basis_sets,&
73 : write_basis
74 : USE physcon, ONLY: evolt
75 : USE powell, ONLY: powell_optimize
76 : USE qs_environment, ONLY: qs_init
77 : USE qs_environment_types, ONLY: get_qs_env,&
78 : qs_env_create,&
79 : qs_env_part_release,&
80 : qs_env_release,&
81 : qs_environment_type
82 : USE qs_kind_types, ONLY: get_qs_kind_set,&
83 : qs_kind_type
84 : USE qs_ks_types, ONLY: get_ks_env,&
85 : qs_ks_env_type,&
86 : set_ks_env
87 : USE qs_mo_types, ONLY: allocate_mo_set,&
88 : deallocate_mo_set,&
89 : get_mo_set,&
90 : init_mo_set,&
91 : mo_set_type
92 : USE qs_neighbor_list_types, ONLY: neighbor_list_set_p_type,&
93 : release_neighbor_list_sets
94 : USE qs_neighbor_lists, ONLY: build_qs_neighbor_lists
95 : USE qs_overlap, ONLY: build_overlap_matrix
96 : #include "./base/base_uses.f90"
97 :
98 : IMPLICIT NONE
99 : PRIVATE
100 :
101 : PUBLIC :: run_optimize_basis
102 :
103 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'optimize_basis'
104 :
105 : CONTAINS
106 :
107 : ! **************************************************************************************************
108 : !> \brief main entry point for methods aimed at optimizing basis sets
109 : !> \param input_declaration ...
110 : !> \param root_section ...
111 : !> \param para_env ...
112 : !> \param globenv ...
113 : !> \author Florian Schiffmann
114 : !> Jan Wilhelm, 08/2026: Add run_frontier_orbital_screening
115 : ! **************************************************************************************************
116 8 : SUBROUTINE run_optimize_basis(input_declaration, root_section, para_env, globenv)
117 : TYPE(section_type), POINTER :: input_declaration
118 : TYPE(section_vals_type), POINTER :: root_section
119 : TYPE(mp_para_env_type), POINTER :: para_env
120 : TYPE(global_environment_type), POINTER :: globenv
121 :
122 : CHARACTER(len=*), PARAMETER :: routineN = 'run_optimize_basis'
123 :
124 : INTEGER :: handle
125 : LOGICAL :: frontier_orbitals_explicit, &
126 : frontier_screening_explicit
127 8 : TYPE(basis_optimization_type) :: opt_bas
128 : TYPE(section_vals_type), POINTER :: frontier_orbitals_section, &
129 : frontier_screening_section, &
130 : optbas_section
131 :
132 8 : CALL timeset(routineN, handle)
133 :
134 8 : optbas_section => section_vals_get_subs_vals(root_section, "OPTIMIZE_BASIS")
135 8 : frontier_orbitals_section => section_vals_get_subs_vals(optbas_section, "FRONTIER_ORBITALS")
136 : frontier_screening_section => &
137 8 : section_vals_get_subs_vals(optbas_section, "FRONTIER_ORBITAL_SCREENING")
138 8 : CALL section_vals_get(frontier_orbitals_section, explicit=frontier_orbitals_explicit)
139 8 : CALL section_vals_get(frontier_screening_section, explicit=frontier_screening_explicit)
140 :
141 8 : IF (frontier_orbitals_explicit .AND. frontier_screening_explicit) THEN
142 0 : CPABORT("FRONTIER_ORBITALS and FRONTIER_ORBITAL_SCREENING cannot be activated together")
143 : END IF
144 :
145 8 : IF (frontier_screening_explicit) THEN
146 : CALL run_frontier_orbital_screening( &
147 2 : input_declaration, root_section, para_env, globenv, frontier_screening_section, driver_para_opt_basis)
148 : ELSE
149 6 : CALL optimize_basis_init_read_input(opt_bas, root_section, para_env)
150 6 : CALL driver_para_opt_basis(opt_bas, input_declaration, para_env, globenv)
151 6 : CALL deallocate_basis_optimization_type(opt_bas)
152 : END IF
153 :
154 8 : CALL timestop(handle)
155 :
156 8 : END SUBROUTINE run_optimize_basis
157 :
158 : ! **************************************************************************************************
159 : !> \brief driver routine for the parallel part of the method
160 : !> \param opt_bas ...
161 : !> \param input_declaration ...
162 : !> \param para_env ...
163 : !> \param globenv ...
164 : !> \param training_input ...
165 : !> \param reference ...
166 : !> \author Florian Schiffmann
167 : ! **************************************************************************************************
168 :
169 8 : SUBROUTINE driver_para_opt_basis(opt_bas, input_declaration, para_env, globenv, training_input, reference)
170 : TYPE(basis_optimization_type) :: opt_bas
171 : TYPE(section_type), POINTER :: input_declaration
172 : TYPE(mp_para_env_type), POINTER :: para_env
173 : TYPE(global_environment_type), POINTER :: globenv
174 : TYPE(section_vals_type), OPTIONAL, POINTER :: training_input
175 : TYPE(frontier_orbitals_reference_type), &
176 : DIMENSION(:), INTENT(IN), OPTIONAL, TARGET :: reference
177 :
178 : CHARACTER(len=*), PARAMETER :: routineN = 'driver_para_opt_basis'
179 :
180 : INTEGER :: handle, n_groups_created
181 : TYPE(mp_comm_type) :: opt_group
182 : INTEGER, DIMENSION(:), POINTER :: group_distribution_p
183 16 : INTEGER, DIMENSION(0:para_env%num_pe-1), TARGET :: group_distribution
184 :
185 8 : CALL timeset(routineN, handle)
186 8 : group_distribution_p => group_distribution
187 : CALL opt_group%from_split(para_env, n_groups_created, group_distribution_p, &
188 8 : n_subgroups=SIZE(opt_bas%group_partition), group_partition=opt_bas%group_partition)
189 8 : opt_bas%opt_id = group_distribution(para_env%mepos) + 1
190 8 : opt_bas%n_groups_created = n_groups_created
191 24 : ALLOCATE (opt_bas%sub_sources(0:para_env%num_pe - 1))
192 :
193 8 : IF (PRESENT(training_input)) THEN
194 2 : CPASSERT(PRESENT(reference))
195 : CALL driver_optimization_para_low(opt_bas, input_declaration, para_env, opt_group, &
196 2 : globenv, training_input, reference)
197 : ELSE
198 6 : CALL driver_optimization_para_low(opt_bas, input_declaration, para_env, opt_group, globenv)
199 : END IF
200 :
201 8 : CALL opt_group%free()
202 8 : CALL timestop(handle)
203 :
204 8 : END SUBROUTINE driver_para_opt_basis
205 :
206 : ! **************************************************************************************************
207 : !> \brief low level optimization routine includes initialization of the subsytems
208 : !> powell optimizer and deallocation of the various force envs
209 : !> \param opt_bas ...
210 : !> \param input_declaration ...
211 : !> \param para_env_top ...
212 : !> \param mpi_comm_opt ...
213 : !> \param globenv ...
214 : !> \param training_input ...
215 : !> \param reference ...
216 : !> \author Florian Schiffmann
217 : ! **************************************************************************************************
218 :
219 8 : SUBROUTINE driver_optimization_para_low(opt_bas, input_declaration, para_env_top, mpi_comm_opt, &
220 8 : globenv, training_input, reference)
221 : TYPE(basis_optimization_type) :: opt_bas
222 : TYPE(section_type), POINTER :: input_declaration
223 : TYPE(mp_para_env_type), POINTER :: para_env_top
224 : TYPE(mp_comm_type), INTENT(IN) :: mpi_comm_opt
225 : TYPE(global_environment_type), POINTER :: globenv
226 : TYPE(section_vals_type), OPTIONAL, POINTER :: training_input
227 : TYPE(frontier_orbitals_reference_type), &
228 : DIMENSION(:), INTENT(IN), OPTIONAL, TARGET :: reference
229 :
230 : CHARACTER(len=*), PARAMETER :: routineN = 'driver_optimization_para_low'
231 :
232 : INTEGER :: handle, icalc, iopt, is, mp_id, &
233 : outer_print_level, stat
234 : INTEGER, ALLOCATABLE, DIMENSION(:) :: f_env_id
235 : LOGICAL :: use_direct_qs, write_basis
236 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: tot_time
237 8 : TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:) :: matrix_S_inv
238 : TYPE(cp_logger_type), POINTER :: logger
239 : TYPE(f_env_type), POINTER :: f_env
240 : TYPE(frontier_orbitals_reference_type), &
241 8 : ALLOCATABLE, DIMENSION(:), TARGET :: local_reference
242 : TYPE(frontier_orbitals_reference_type), &
243 8 : DIMENSION(:), POINTER :: active_reference
244 : TYPE(frontier_orbitals_result_type), ALLOCATABLE, &
245 8 : DIMENSION(:) :: initial_info, optimized_info
246 : TYPE(mp_para_env_type), POINTER :: para_env
247 : TYPE(qs_environment_type), ALLOCATABLE, &
248 8 : DIMENSION(:), TARGET :: training_qs_env
249 :
250 8 : NULLIFY (active_reference, f_env, logger)
251 :
252 8 : CALL timeset(routineN, handle)
253 :
254 : ! ====== initialize the f_env and precompute some matrices =====
255 8 : mp_id = opt_bas%opt_id
256 8 : use_direct_qs = opt_bas%method == method_mo_fit_occ_virtual
257 8 : NULLIFY (para_env, f_env)
258 37 : ALLOCATE (f_env_id(SIZE(opt_bas%comp_group(mp_id)%member_list)), source=-1)
259 24 : ALLOCATE (tot_time(opt_bas%ncombinations*opt_bas%ntraining_sets))
260 8 : IF (opt_bas%method == method_mo_fit_occ) THEN
261 21 : ALLOCATE (matrix_s_inv(SIZE(opt_bas%comp_group(mp_id)%member_list)))
262 : ELSE
263 16 : ALLOCATE (initial_info(opt_bas%ncombinations*opt_bas%ntraining_sets))
264 16 : ALLOCATE (optimized_info(opt_bas%ncombinations*opt_bas%ntraining_sets))
265 4 : IF (PRESENT(reference)) THEN
266 2 : active_reference => reference
267 : ELSE
268 8 : ALLOCATE (local_reference(SIZE(opt_bas%comp_group(mp_id)%member_list)))
269 2 : active_reference => local_reference
270 : END IF
271 : END IF
272 :
273 8 : ALLOCATE (para_env)
274 8 : para_env = mpi_comm_opt
275 :
276 8 : is = -1
277 8 : IF (para_env%is_source()) is = para_env_top%mepos
278 8 : CALL para_env_top%allgather(is, opt_bas%sub_sources)
279 :
280 8 : IF (use_direct_qs) THEN
281 16 : ALLOCATE (training_qs_env(SIZE(opt_bas%comp_group(mp_id)%member_list)))
282 4 : logger => cp_get_default_logger()
283 4 : outer_print_level = logger%iter_info%print_level
284 4 : logger%iter_info%print_level = silent_print_level
285 4 : IF (PRESENT(training_input)) THEN
286 : CALL init_training_qs_envs(opt_bas, training_qs_env, input_declaration, para_env, globenv, &
287 2 : training_input=training_input)
288 : ELSE
289 : CALL init_training_qs_envs(opt_bas, training_qs_env, input_declaration, para_env, globenv, &
290 2 : reference=local_reference)
291 : END IF
292 : ELSE
293 : CALL init_training_force_envs(opt_bas, f_env_id, input_declaration, para_env, mpi_comm_opt, &
294 4 : matrix_s_inv=matrix_s_inv)
295 : END IF
296 :
297 8 : CALL init_free_vars(opt_bas)
298 8 : IF (opt_bas%method == method_mo_fit_occ_virtual) THEN
299 : ! Store the normalized coefficient representation used by the basis code.
300 4 : CALL update_free_vars(opt_bas)
301 4 : CALL init_free_vars(opt_bas)
302 84 : ALLOCATE (opt_bas%x_initial, source=opt_bas%x_opt)
303 : END IF
304 8 : tot_time = 0.0_dp
305 :
306 : ! ======= The real optimization loop =======
307 526 : DO iopt = 0, opt_bas%powell_param%maxfun
308 632 : SELECT CASE (opt_bas%method)
309 : CASE (method_mo_fit_occ)
310 : CALL compute_residuum_vectors(opt_bas, f_env_id, matrix_S_inv, tot_time, &
311 114 : para_env_top, para_env, iopt)
312 : CASE (method_mo_fit_occ_virtual)
313 404 : IF (iopt == 0) THEN
314 : CALL compute_frontier_orbitals_objective( &
315 : opt_bas, f_env_id, active_reference, tot_time, &
316 4 : para_env_top, para_env, initial_info, training_qs_env)
317 : ELSE
318 : CALL compute_frontier_orbitals_objective( &
319 : opt_bas, f_env_id, active_reference, tot_time, &
320 400 : para_env_top, para_env, qs_envs=training_qs_env)
321 : END IF
322 : CASE DEFAULT
323 518 : CPABORT("Unknown basis optimization method")
324 : END SELECT
325 518 : IF (para_env_top%is_source()) THEN
326 259 : CALL powell_optimize(opt_bas%powell_param%nvar, opt_bas%x_opt, opt_bas%powell_param)
327 : END IF
328 518 : CALL para_env_top%bcast(opt_bas%powell_param%state)
329 518 : CALL para_env_top%bcast(opt_bas%x_opt)
330 518 : CALL update_free_vars(opt_bas)
331 : write_basis = opt_bas%method == method_mo_fit_occ .AND. &
332 518 : MOD(iopt, opt_bas%write_frequency) == 0
333 : CALL update_derived_basis_sets(opt_bas, write_basis, opt_bas%output_basis_file, &
334 518 : para_env_top)
335 526 : IF (opt_bas%powell_param%state == -1) EXIT
336 : END DO
337 :
338 : ! ======= Update the basis set and print the final basis =======
339 8 : IF (para_env_top%is_source()) THEN
340 4 : opt_bas%powell_param%state = 8
341 4 : CALL powell_optimize(opt_bas%powell_param%nvar, opt_bas%x_opt, opt_bas%powell_param)
342 : END IF
343 :
344 8 : CALL para_env_top%bcast(opt_bas%x_opt)
345 8 : CALL update_free_vars(opt_bas)
346 8 : IF (opt_bas%method == method_mo_fit_occ_virtual) THEN
347 : ! Report the actual best Powell vector, rather than the final trial point.
348 : CALL compute_frontier_orbitals_objective( &
349 : opt_bas, f_env_id, active_reference, tot_time, &
350 4 : para_env_top, para_env, optimized_info, training_qs_env)
351 4 : IF (.NOT. opt_bas%quiet_output) THEN
352 : CALL print_frontier_orbitals_info( &
353 : opt_bas, active_reference, initial_info, optimized_info, &
354 2 : para_env_top, para_env)
355 : END IF
356 : END IF
357 : CALL update_derived_basis_sets(opt_bas,.NOT. opt_bas%quiet_output, opt_bas%output_basis_file, &
358 8 : para_env_top)
359 :
360 : ! ====== get rid of the f_env again =====
361 :
362 21 : DO icalc = SIZE(opt_bas%comp_group(mp_id)%member_list), 1, -1
363 13 : IF (opt_bas%method == method_mo_fit_occ_virtual .AND. ALLOCATED(local_reference)) THEN
364 2 : CALL frontier_orbitals_reference_release(local_reference(icalc))
365 : END IF
366 21 : IF (use_direct_qs) THEN
367 4 : CALL qs_env_release(training_qs_env(icalc))
368 : ELSE
369 9 : CALL f_env_get_from_id(f_env_id(icalc), f_env)
370 9 : CALL destroy_force_env(f_env_id(icalc), stat)
371 : END IF
372 : END DO
373 8 : IF (ALLOCATED(training_qs_env)) THEN
374 4 : DEALLOCATE (training_qs_env)
375 4 : logger%iter_info%print_level = outer_print_level
376 : END IF
377 8 : DEALLOCATE (f_env_id); DEALLOCATE (tot_time)
378 8 : IF (ALLOCATED(initial_info)) DEALLOCATE (initial_info)
379 8 : IF (ALLOCATED(optimized_info)) DEALLOCATE (optimized_info)
380 10 : IF (ALLOCATED(local_reference)) DEALLOCATE (local_reference)
381 8 : CALL cp_fm_release(matrix_s_inv)
382 8 : CALL mp_para_env_release(para_env)
383 8 : CALL timestop(handle)
384 :
385 16 : END SUBROUTINE driver_optimization_para_low
386 :
387 : ! **************************************************************************************************
388 : !> \brief compute all ingredients for powell optimizer. Rho_diff,
389 : !> condition number, energy,... for all ttraining sets in
390 : !> the computational group
391 : !> \param opt_bas ...
392 : !> \param f_env_id ...
393 : !> \param matrix_S_inv ...
394 : !> \param tot_time ...
395 : !> \param para_env_top ...
396 : !> \param para_env ...
397 : !> \param iopt ...
398 : ! **************************************************************************************************
399 :
400 114 : SUBROUTINE compute_residuum_vectors(opt_bas, f_env_id, matrix_S_inv, tot_time, &
401 : para_env_top, para_env, iopt)
402 : TYPE(basis_optimization_type) :: opt_bas
403 : INTEGER, ALLOCATABLE, DIMENSION(:) :: f_env_id
404 : TYPE(cp_fm_type), DIMENSION(:), INTENT(IN) :: matrix_S_inv
405 : REAL(KIND=dp), DIMENSION(:) :: tot_time
406 : TYPE(mp_para_env_type), POINTER :: para_env_top, para_env
407 : INTEGER :: iopt
408 :
409 : CHARACTER(len=*), PARAMETER :: routineN = 'compute_residuum_vectors'
410 :
411 : CHARACTER(len=8) :: basis_type
412 : INTEGER :: bas_id, handle, icalc, icomb, ispin, &
413 : mp_id, my_id, nao, ncalc, nelectron, &
414 : nmo, nspins, set_id
415 : REAL(KIND=dp) :: flexible_electron_count, maxocc, n_el_f
416 114 : REAL(KIND=dp), DIMENSION(:), POINTER :: cond_vec, energy, f_vec, my_time, &
417 114 : start_time
418 114 : REAL(KIND=dp), DIMENSION(:, :), POINTER :: gdata
419 : TYPE(cp_fm_struct_type), POINTER :: fm_struct
420 : TYPE(cp_fm_type), POINTER :: mo_coeff
421 114 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrix_ks, matrix_s_aux, matrix_s_aux_orb
422 : TYPE(f_env_type), POINTER :: f_env
423 : TYPE(force_env_type), POINTER :: force_env
424 114 : TYPE(mo_set_type), ALLOCATABLE, DIMENSION(:) :: mos_aux
425 114 : TYPE(mo_set_type), DIMENSION(:), POINTER :: mos
426 : TYPE(neighbor_list_set_p_type), DIMENSION(:), &
427 114 : POINTER :: sab_aux, sab_aux_orb
428 : TYPE(qs_environment_type), POINTER :: qs_env
429 114 : TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
430 : TYPE(qs_ks_env_type), POINTER :: ks_env
431 :
432 114 : CALL timeset(routineN, handle)
433 :
434 114 : basis_type = "AUX_OPT"
435 : !
436 114 : ncalc = opt_bas%ncombinations*opt_bas%ntraining_sets
437 342 : ALLOCATE (gdata(ncalc, 4))
438 114 : f_vec => gdata(:, 1)
439 114 : my_time => gdata(:, 2)
440 114 : cond_vec => gdata(:, 3)
441 114 : energy => gdata(:, 4)
442 : !
443 1986 : f_vec = 0.0_dp; cond_vec = 0.0_dp; my_time = 0.0_dp; energy = 0.0_dp
444 114 : mp_id = opt_bas%opt_id
445 342 : ALLOCATE (start_time(SIZE(opt_bas%comp_group(mp_id)%member_list)))
446 : !
447 348 : DO icalc = 1, SIZE(opt_bas%comp_group(mp_id)%member_list)
448 234 : my_id = opt_bas%comp_group(mp_id)%member_list(icalc) + 1
449 : ! setup timings
450 234 : start_time(icalc) = m_walltime()
451 :
452 234 : NULLIFY (matrix_s_aux_orb, matrix_s_aux)
453 234 : CALL get_set_and_basis_id(opt_bas%comp_group(mp_id)%member_list(icalc), opt_bas, set_id, bas_id)
454 234 : CALL f_env_get_from_id(f_env_id(icalc), f_env)
455 234 : force_env => f_env%force_env
456 234 : CALL force_env_get(force_env, qs_env=qs_env)
457 234 : CALL get_qs_env(qs_env, ks_env=ks_env)
458 234 : CALL update_basis_set(opt_bas, bas_id, basis_type, qs_env)
459 234 : NULLIFY (sab_aux, sab_aux_orb)
460 234 : CALL optbas_build_neighborlist(qs_env, sab_aux, sab_aux_orb, basis_type)
461 : CALL build_overlap_matrix(ks_env, matrix_s=matrix_s_aux, &
462 : basis_type_a=basis_type, &
463 : basis_type_b=basis_type, &
464 234 : sab_nl=sab_aux)
465 : CALL build_overlap_matrix(ks_env, matrix_s=matrix_s_aux_orb, &
466 : basis_type_a=basis_type, &
467 : basis_type_b="ORB", &
468 234 : sab_nl=sab_aux_orb)
469 234 : CALL release_neighbor_list_sets(sab_aux)
470 234 : CALL release_neighbor_list_sets(sab_aux_orb)
471 234 : CALL get_qs_env(qs_env, mos=mos, matrix_ks=matrix_ks)
472 :
473 234 : nspins = SIZE(mos)
474 936 : ALLOCATE (mos_aux(nspins))
475 234 : CALL get_qs_env(qs_env, qs_kind_set=qs_kind_set)
476 234 : CALL get_qs_kind_set(qs_kind_set, nsgf=nao, basis_type=basis_type)
477 468 : DO ispin = 1, nspins
478 : CALL get_mo_set(mo_set=mos(ispin), mo_coeff=mo_coeff, maxocc=maxocc, nelectron=nelectron, &
479 234 : n_el_f=n_el_f, nmo=nmo, flexible_electron_count=flexible_electron_count)
480 : CALL cp_fm_struct_create(fm_struct, nrow_global=nao, ncol_global=nmo, &
481 : context=mo_coeff%matrix_struct%context, &
482 234 : para_env=mo_coeff%matrix_struct%para_env)
483 : CALL allocate_mo_set(mos_aux(ispin), nao, nmo, nelectron, &
484 234 : n_el_f, maxocc, flexible_electron_count)
485 234 : CALL init_mo_set(mo_set=mos_aux(ispin), fm_struct=fm_struct, name="MO_AUX")
486 702 : CALL cp_fm_struct_release(fm_struct)
487 : END DO
488 :
489 234 : CALL fit_mo_coeffs(matrix_s_aux, matrix_s_aux_orb, mos, mos_aux)
490 : CALL evaluate_optvals(mos, mos_aux, matrix_ks, matrix_s_aux_orb(1)%matrix, &
491 : matrix_s_aux(1)%matrix, matrix_S_inv(icalc), &
492 234 : f_vec(my_id), energy(my_id), cond_vec(my_id))
493 :
494 468 : DO ispin = 1, nspins
495 468 : CALL deallocate_mo_set(mos_aux(ispin))
496 : END DO
497 234 : DEALLOCATE (mos_aux)
498 234 : IF (ASSOCIATED(matrix_s_aux)) CALL dbcsr_deallocate_matrix_set(matrix_s_aux)
499 234 : IF (ASSOCIATED(matrix_s_aux_orb)) CALL dbcsr_deallocate_matrix_set(matrix_s_aux_orb)
500 :
501 582 : my_time(my_id) = m_walltime() - start_time(icalc)
502 : END DO
503 :
504 114 : DEALLOCATE (start_time)
505 :
506 114 : IF (.NOT. para_env%is_source()) THEN
507 0 : f_vec = 0.0_dp; cond_vec = 0.0_dp; my_time = 0.0_dp; energy = 0.0_dp
508 : END IF
509 : ! collect date from all subgroup ionodes on the main ionode
510 4770 : CALL para_env_top%sum(gdata)
511 :
512 114 : opt_bas%powell_param%f = 0.0_dp
513 114 : IF (para_env_top%is_source()) THEN
514 291 : DO icalc = 1, SIZE(f_vec)
515 234 : icomb = MOD(icalc - 1, opt_bas%ncombinations)
516 : opt_bas%powell_param%f = opt_bas%powell_param%f + &
517 234 : (f_vec(icalc) + energy(icalc))*opt_bas%fval_weight(icomb)
518 291 : IF (opt_bas%use_condition_number) THEN
519 : opt_bas%powell_param%f = opt_bas%powell_param%f + &
520 234 : LOG(cond_vec(icalc))*opt_bas%condition_weight(icomb)
521 : END IF
522 : END DO
523 : ELSE
524 993 : f_vec = 0.0_dp; cond_vec = 0.0_dp; my_time = 0.0_dp; energy = 0.0_dp
525 : END IF
526 114 : CALL para_env_top%bcast(opt_bas%powell_param%f)
527 :
528 : ! output info if required
529 114 : CALL output_opt_info(f_vec, cond_vec, my_time, tot_time, opt_bas, iopt, para_env_top)
530 114 : DEALLOCATE (gdata)
531 :
532 114 : CALL para_env_top%sync()
533 :
534 114 : CALL timestop(handle)
535 :
536 228 : END SUBROUTINE compute_residuum_vectors
537 :
538 : ! **************************************************************************************************
539 : !> \brief Evaluate the frozen-density frontier-orbital objective.
540 : !> \param opt_bas basis optimization settings and current parameters
541 : !> \param f_env_id force environments for locally assigned calculations
542 : !> \param reference cached full reference eigensystems
543 : !> \param tot_time accumulated timings for output
544 : !> \param para_env_top top-level communicator
545 : !> \param para_env calculation-group communicator
546 : !> \param info ...
547 : !> \param qs_envs ...
548 : ! **************************************************************************************************
549 832 : SUBROUTINE compute_frontier_orbitals_objective(opt_bas, f_env_id, reference, tot_time, &
550 816 : para_env_top, para_env, info, qs_envs)
551 : TYPE(basis_optimization_type) :: opt_bas
552 : INTEGER, ALLOCATABLE, DIMENSION(:) :: f_env_id
553 : TYPE(frontier_orbitals_reference_type), &
554 : DIMENSION(:), INTENT(IN) :: reference
555 : REAL(KIND=dp), DIMENSION(:) :: tot_time
556 : TYPE(mp_para_env_type), POINTER :: para_env_top, para_env
557 : TYPE(frontier_orbitals_result_type), &
558 : DIMENSION(:), INTENT(OUT), OPTIONAL :: info
559 : TYPE(qs_environment_type), DIMENSION(:), &
560 : OPTIONAL, TARGET :: qs_envs
561 :
562 : CHARACTER(len=*), PARAMETER :: routineN = 'compute_frontier_orbitals_objective'
563 :
564 : CHARACTER(len=8) :: basis_type
565 : INTEGER :: bas_id, handle, icalc, icomb, icont, &
566 : ikind, ipgf, iset, ix, mp_id, my_id, &
567 : ncalc, set_id
568 : REAL(KIND=dp) :: coefficient_loss, contribution
569 408 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: coefficients_current
570 408 : REAL(KIND=dp), DIMENSION(:), POINTER :: start_time
571 408 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrix_s_aux, matrix_s_aux_orb
572 : TYPE(f_env_type), POINTER :: f_env
573 : TYPE(force_env_type), POINTER :: force_env
574 : TYPE(frontier_orbitals_result_type), ALLOCATABLE, &
575 408 : DIMENSION(:) :: results
576 : TYPE(neighbor_list_set_p_type), DIMENSION(:), &
577 408 : POINTER :: sab_aux, sab_aux_orb
578 : TYPE(qs_environment_type), POINTER :: qs_env
579 : TYPE(qs_ks_env_type), POINTER :: ks_env
580 :
581 408 : CALL timeset(routineN, handle)
582 :
583 408 : basis_type = "AUX_OPT"
584 408 : ncalc = opt_bas%ncombinations*opt_bas%ntraining_sets
585 1632 : ALLOCATE (results(ncalc))
586 8568 : ALLOCATE (coefficients_current, source=opt_bas%x_opt)
587 1224 : DO ikind = 1, opt_bas%nkind
588 2040 : DO iset = 1, opt_bas%kind_basis(ikind)%flex_basis(0)%nsets
589 6936 : DO ipgf = 1, opt_bas%kind_basis(ikind)%flex_basis(0)%subset(iset)%nexp
590 29784 : DO icont = 1, opt_bas%kind_basis(ikind)%flex_basis(0)%subset(iset)%ncon_tot
591 28968 : IF (opt_bas%kind_basis(ikind)%flex_basis(0)%subset(iset)%opt_coeff(ipgf, icont)) THEN
592 7344 : ix = opt_bas%kind_basis(ikind)%flex_basis(0)%subset(iset)%coeff_x_ind(ipgf, icont)
593 : coefficients_current(ix) = &
594 7344 : opt_bas%kind_basis(ikind)%flex_basis(0)%subset(iset)%coeff(ipgf, icont)
595 : END IF
596 : END DO
597 : END DO
598 : END DO
599 : END DO
600 408 : coefficient_loss = 0.0_dp
601 7752 : IF (SUM(opt_bas%x_initial**2) > TINY(1.0_dp)) THEN
602 : coefficient_loss = SUM((coefficients_current - opt_bas%x_initial)**2)/ &
603 15096 : SUM(opt_bas%x_initial**2)
604 : END IF
605 408 : mp_id = opt_bas%opt_id
606 1224 : ALLOCATE (start_time(SIZE(opt_bas%comp_group(mp_id)%member_list)))
607 :
608 816 : DO icalc = 1, SIZE(opt_bas%comp_group(mp_id)%member_list)
609 408 : my_id = opt_bas%comp_group(mp_id)%member_list(icalc) + 1
610 408 : start_time(icalc) = m_walltime()
611 :
612 408 : NULLIFY (ks_env, matrix_s_aux, matrix_s_aux_orb, sab_aux, sab_aux_orb)
613 : CALL get_set_and_basis_id(opt_bas%comp_group(mp_id)%member_list(icalc), opt_bas, &
614 408 : bas_id=bas_id, set_id=set_id)
615 408 : IF (PRESENT(qs_envs)) THEN
616 408 : qs_env => qs_envs(icalc)
617 : ELSE
618 0 : CALL f_env_get_from_id(f_env_id(icalc), f_env)
619 0 : force_env => f_env%force_env
620 0 : CALL force_env_get(force_env, qs_env=qs_env)
621 : END IF
622 408 : CALL update_basis_set(opt_bas, bas_id, basis_type, qs_env)
623 408 : CALL optbas_build_neighborlist(qs_env, sab_aux, sab_aux_orb, basis_type)
624 408 : CALL get_qs_env(qs_env, ks_env=ks_env)
625 : CALL build_overlap_matrix(ks_env, matrix_s=matrix_s_aux, &
626 408 : basis_type_a=basis_type, basis_type_b=basis_type, sab_nl=sab_aux)
627 : CALL build_overlap_matrix(ks_env, matrix_s=matrix_s_aux_orb, &
628 408 : basis_type_a=basis_type, basis_type_b="ORB", sab_nl=sab_aux_orb)
629 408 : CALL release_neighbor_list_sets(sab_aux)
630 408 : CALL release_neighbor_list_sets(sab_aux_orb)
631 :
632 : CALL evaluate_frontier_orbitals_objective( &
633 : reference(icalc), matrix_s_aux(1)%matrix, matrix_s_aux_orb(1)%matrix, &
634 : opt_bas%virtual_energy_cutoff, opt_bas%virtual_energy_smoothing, &
635 408 : opt_bas%gap_energy_scale, results(my_id))
636 408 : results(my_id)%reference_condition_number = reference(icalc)%condition_number
637 408 : results(my_id)%number_reference_orbitals = reference(icalc)%number_reference_orbitals
638 408 : results(my_id)%calculation_time = m_walltime() - start_time(icalc)
639 :
640 408 : IF (ASSOCIATED(matrix_s_aux)) CALL dbcsr_deallocate_matrix_set(matrix_s_aux)
641 816 : IF (ASSOCIATED(matrix_s_aux_orb)) CALL dbcsr_deallocate_matrix_set(matrix_s_aux_orb)
642 : END DO
643 408 : DEALLOCATE (start_time)
644 :
645 408 : CALL reduce_frontier_orbitals_results(results, para_env_top, para_env)
646 408 : IF (PRESENT(info)) THEN
647 8 : CPASSERT(SIZE(info) == ncalc)
648 16 : info = results
649 : END IF
650 :
651 408 : opt_bas%powell_param%f = 0.0_dp
652 408 : IF (para_env_top%is_source()) THEN
653 408 : DO icalc = 1, ncalc
654 204 : icomb = MOD(icalc - 1, opt_bas%ncombinations)
655 : contribution = opt_bas%occupied_weight*results(icalc)%loss_occupied_subspace + &
656 : opt_bas%virtual_weight*results(icalc)%loss_virtual_subspace + &
657 : opt_bas%empty_overlap_weight*results(icalc)%loss_empty_subspace + &
658 : opt_bas%gap_weight*results(icalc)%loss_gap + &
659 204 : opt_bas%coefficient_weight*coefficient_loss
660 204 : IF (opt_bas%use_condition_number) THEN
661 : contribution = contribution + opt_bas%condition_weight(icomb)* &
662 102 : LOG10(results(icalc)%condition_number)
663 : END IF
664 : opt_bas%powell_param%f = opt_bas%powell_param%f + &
665 204 : opt_bas%fval_weight(icomb)*contribution
666 408 : tot_time(icalc) = tot_time(icalc) + results(icalc)%calculation_time
667 : END DO
668 : END IF
669 408 : CALL para_env_top%bcast(opt_bas%powell_param%f)
670 408 : DEALLOCATE (coefficients_current, results)
671 :
672 408 : CALL para_env_top%sync()
673 408 : CALL timestop(handle)
674 :
675 416 : END SUBROUTINE compute_frontier_orbitals_objective
676 :
677 : ! **************************************************************************************************
678 : !> \brief Collect frontier-orbital results from all calculation groups.
679 : !> \param results frontier-orbital results for every training calculation
680 : !> \param para_env_top top-level communicator
681 : !> \param para_env calculation-group communicator
682 : ! **************************************************************************************************
683 408 : SUBROUTINE reduce_frontier_orbitals_results(results, para_env_top, para_env)
684 : TYPE(frontier_orbitals_result_type), &
685 : DIMENSION(:), INTENT(INOUT) :: results
686 : TYPE(mp_para_env_type), POINTER :: para_env_top, para_env
687 :
688 612 : IF (.NOT. para_env%is_source()) results = frontier_orbitals_result_type()
689 1224 : CALL para_env_top%sum(results%loss_occupied_subspace)
690 1224 : CALL para_env_top%sum(results%loss_virtual_subspace)
691 1224 : CALL para_env_top%sum(results%loss_empty_subspace)
692 1224 : CALL para_env_top%sum(results%loss_gap)
693 1224 : CALL para_env_top%sum(results%occupied_subspace_overlap)
694 1224 : CALL para_env_top%sum(results%virtual_subspace_similarity)
695 1224 : CALL para_env_top%sum(results%empty_subspace_overlap)
696 1224 : CALL para_env_top%sum(results%gap_reference)
697 1224 : CALL para_env_top%sum(results%gap_candidate)
698 1224 : CALL para_env_top%sum(results%condition_number)
699 1224 : CALL para_env_top%sum(results%reference_condition_number)
700 1224 : CALL para_env_top%sum(results%calculation_time)
701 1224 : CALL para_env_top%sum(results%number_candidate_orbitals)
702 1224 : CALL para_env_top%sum(results%number_reference_orbitals)
703 :
704 408 : END SUBROUTINE reduce_frontier_orbitals_results
705 :
706 : ! **************************************************************************************************
707 : !> \brief Print initial-to-optimized frontier-orbital information for every training calculation.
708 : !> \param opt_bas basis optimization settings
709 : !> \param reference locally held reference data and basis metadata
710 : !> \param initial initial-small-basis results
711 : !> \param optimized optimized-small-basis results
712 : !> \param para_env_top top-level communicator
713 : !> \param para_env calculation-group communicator
714 : ! **************************************************************************************************
715 2 : SUBROUTINE print_frontier_orbitals_info(opt_bas, reference, initial, optimized, &
716 : para_env_top, para_env)
717 : TYPE(basis_optimization_type), INTENT(IN) :: opt_bas
718 : TYPE(frontier_orbitals_reference_type), &
719 : DIMENSION(:), INTENT(IN) :: reference
720 : TYPE(frontier_orbitals_result_type), &
721 : DIMENSION(:), INTENT(IN) :: initial, optimized
722 : TYPE(mp_para_env_type), POINTER :: para_env_top, para_env
723 :
724 : CHARACTER(LEN=17) :: basis_label
725 : CHARACTER(LEN=default_string_length), &
726 2 : ALLOCATABLE, DIMENSION(:) :: candidate_basis, element, reference_basis
727 : INTEGER :: bas_id, icalc, ikind, iset, max_kinds, &
728 : my_id, ncalc, unit_nr
729 : INTEGER, ALLOCATABLE, DIMENSION(:) :: kind_count
730 : INTEGER, ALLOCATABLE, DIMENSION(:, :, :, :) :: metadata
731 : TYPE(cp_logger_type), POINTER :: logger
732 :
733 2 : ncalc = opt_bas%ncombinations*opt_bas%ntraining_sets
734 2 : CPASSERT(SIZE(initial) == ncalc)
735 2 : CPASSERT(SIZE(optimized) == ncalc)
736 :
737 2 : max_kinds = 0
738 4 : DO icalc = 1, SIZE(reference)
739 4 : max_kinds = MAX(max_kinds, reference(icalc)%number_kinds)
740 : END DO
741 2 : CALL para_env_top%max(max_kinds)
742 6 : ALLOCATE (kind_count(ncalc), source=0)
743 12 : ALLOCATE (metadata(ncalc, max_kinds, 3, default_string_length), source=0)
744 :
745 2 : IF (para_env%is_source()) THEN
746 2 : DO icalc = 1, SIZE(reference)
747 1 : my_id = opt_bas%comp_group(opt_bas%opt_id)%member_list(icalc) + 1
748 1 : kind_count(my_id) = reference(icalc)%number_kinds
749 4 : DO ikind = 1, reference(icalc)%number_kinds
750 2 : CALL encode_string(reference(icalc)%element_symbol(ikind), metadata(my_id, ikind, 1, :))
751 2 : CALL encode_string(reference(icalc)%reference_basis_name(ikind), metadata(my_id, ikind, 2, :))
752 3 : CALL encode_string(reference(icalc)%candidate_basis_name(ikind), metadata(my_id, ikind, 3, :))
753 : END DO
754 : END DO
755 : END IF
756 2 : CALL para_env_top%sum(kind_count)
757 2 : CALL para_env_top%sum(metadata)
758 :
759 2 : logger => cp_get_default_logger()
760 2 : unit_nr = -1
761 2 : IF (para_env_top%is_source()) unit_nr = cp_logger_get_default_unit_nr(logger)
762 2 : IF (unit_nr > 0) THEN
763 1 : WRITE (unit_nr, '(A)') ""
764 1 : WRITE (unit_nr, '(A)') REPEAT("=", 78)
765 1 : WRITE (unit_nr, '(A)') "BASIS OPTIMIZATION SUMMARY"
766 1 : WRITE (unit_nr, '(A)') REPEAT("=", 78)
767 :
768 2 : DO my_id = 1, ncalc
769 1 : CALL get_set_and_basis_id(my_id - 1, opt_bas, set_id=iset, bas_id=bas_id)
770 1 : WRITE (unit_nr, '(A)') ""
771 1 : WRITE (unit_nr, '(A,A,A,A)') "Reference calculation: ", &
772 2 : TRIM(opt_bas%training_dir(iset)), "/", TRIM(opt_bas%training_input(iset))
773 1 : IF (opt_bas%ncombinations > 1) THEN
774 0 : WRITE (unit_nr, '(A,I0)') "Basis combination: ", bas_id
775 : END IF
776 1 : WRITE (unit_nr, '(A)') ""
777 1 : WRITE (unit_nr, '(A)') "Atomic kind basis sets"
778 1 : WRITE (unit_nr, '(A)') REPEAT("-", 78)
779 0 : ALLOCATE (candidate_basis(kind_count(my_id)), element(kind_count(my_id)), &
780 5 : reference_basis(kind_count(my_id)))
781 3 : DO ikind = 1, kind_count(my_id)
782 2 : CALL decode_string(metadata(my_id, ikind, 1, :), element(ikind))
783 2 : CALL decode_string(metadata(my_id, ikind, 2, :), reference_basis(ikind))
784 3 : CALL decode_string(metadata(my_id, ikind, 3, :), candidate_basis(ikind))
785 : END DO
786 1 : CALL print_frontier_orbital_basis_sets(unit_nr, element, reference_basis, candidate_basis)
787 1 : DEALLOCATE (candidate_basis, element, reference_basis)
788 1 : WRITE (unit_nr, '(A)') ""
789 1 : WRITE (unit_nr, '(A,A)') "Optimized basis file: ", TRIM(opt_bas%output_basis_file)
790 1 : WRITE (unit_nr, '(A)') ""
791 :
792 1 : WRITE (unit_nr, '(A)') "Overall subspace quality and conditioning"
793 1 : WRITE (unit_nr, '(A)') REPEAT("-", 78)
794 1 : basis_label = "Basis"
795 1 : WRITE (unit_nr, '(A17,1X,A4,2(1X,A11),1X,A12,1X,A9,1X,A6)') basis_label, "N_AO", &
796 2 : "Occ.overlap", "Vir.overlap", "Emp.coverage", "κ(S)", "Gap/eV"
797 1 : WRITE (unit_nr, '(A)') REPEAT("-", 78)
798 1 : basis_label = "Ref. basis"
799 : WRITE (unit_nr, '(A17,1X,I4,2(1X,F10.1,A),1X,F11.1,A,1X,ES9.2,1X,F6.3)') &
800 1 : basis_label, initial(my_id)%number_reference_orbitals, &
801 1 : 100.0_dp, "%", 100.0_dp, "%", 100.0_dp, "%", &
802 1 : initial(my_id)%reference_condition_number, &
803 2 : initial(my_id)%gap_reference*evolt
804 1 : basis_label = "Init. small basis"
805 : WRITE (unit_nr, '(A17,1X,I4,2(1X,F10.1,A),1X,F11.1,A,1X,ES9.2,1X,F6.3)') &
806 1 : basis_label, initial(my_id)%number_candidate_orbitals, &
807 1 : 100.0_dp*initial(my_id)%occupied_subspace_overlap, "%", &
808 1 : 100.0_dp*initial(my_id)%virtual_subspace_similarity, "%", &
809 1 : 100.0_dp*initial(my_id)%empty_subspace_overlap, "%", &
810 2 : initial(my_id)%condition_number, initial(my_id)%gap_candidate*evolt
811 1 : basis_label = "Opt. small basis"
812 : WRITE (unit_nr, '(A17,1X,I4,2(1X,F10.1,A),1X,F11.1,A,1X,ES9.2,1X,F6.3)') &
813 1 : basis_label, optimized(my_id)%number_candidate_orbitals, &
814 1 : 100.0_dp*optimized(my_id)%occupied_subspace_overlap, "%", &
815 1 : 100.0_dp*optimized(my_id)%virtual_subspace_similarity, "%", &
816 1 : 100.0_dp*optimized(my_id)%empty_subspace_overlap, "%", &
817 2 : optimized(my_id)%condition_number, optimized(my_id)%gap_candidate*evolt
818 2 : WRITE (unit_nr, '(A)') REPEAT("-", 78)
819 :
820 : END DO
821 :
822 1 : WRITE (unit_nr, '(A)') REPEAT("=", 78)
823 1 : WRITE (unit_nr, '(A)') ""
824 : END IF
825 :
826 2 : DEALLOCATE (kind_count, metadata)
827 :
828 2 : END SUBROUTINE print_frontier_orbitals_info
829 :
830 : ! **************************************************************************************************
831 : !> \brief Encode a string as integers so basis metadata can be reduced across optimizer groups.
832 : !> \param string ...
833 : !> \param encoded ...
834 : ! **************************************************************************************************
835 6 : PURE SUBROUTINE encode_string(string, encoded)
836 : CHARACTER(LEN=*), INTENT(IN) :: string
837 : INTEGER, DIMENSION(:), INTENT(OUT) :: encoded
838 :
839 : INTEGER :: i
840 :
841 486 : encoded = 0
842 60 : DO i = 1, MIN(LEN_TRIM(string), SIZE(encoded))
843 60 : encoded(i) = IACHAR(string(i:i))
844 : END DO
845 :
846 6 : END SUBROUTINE encode_string
847 :
848 : ! **************************************************************************************************
849 : !> \brief Decode integer character codes used to communicate basis metadata.
850 : !> \param encoded ...
851 : !> \param string ...
852 : ! **************************************************************************************************
853 12 : PURE SUBROUTINE decode_string(encoded, string)
854 : INTEGER, DIMENSION(:), INTENT(IN) :: encoded
855 : CHARACTER(LEN=*), INTENT(OUT) :: string
856 :
857 : INTEGER :: i
858 :
859 6 : string = ""
860 60 : DO i = 1, MIN(LEN(string), SIZE(encoded))
861 60 : IF (encoded(i) == 0) EXIT
862 60 : string(i:i) = ACHAR(encoded(i))
863 : END DO
864 :
865 6 : END SUBROUTINE decode_string
866 :
867 : ! **************************************************************************************************
868 : !> \brief Initialize Quickstep environments without starting nested CP2K runs.
869 : !> \param opt_bas ...
870 : !> \param qs_envs ...
871 : !> \param input_declaration ...
872 : !> \param para_env ...
873 : !> \param globenv ...
874 : !> \param training_input ...
875 : !> \param reference ...
876 : ! **************************************************************************************************
877 16 : SUBROUTINE init_training_qs_envs(opt_bas, qs_envs, input_declaration, para_env, globenv, &
878 4 : training_input, reference)
879 : TYPE(basis_optimization_type) :: opt_bas
880 : TYPE(qs_environment_type), DIMENSION(:), &
881 : INTENT(OUT), TARGET :: qs_envs
882 : TYPE(section_type), POINTER :: input_declaration
883 : TYPE(mp_para_env_type), POINTER :: para_env
884 : TYPE(global_environment_type), POINTER :: globenv
885 : TYPE(section_vals_type), OPTIONAL, POINTER :: training_input
886 : TYPE(frontier_orbitals_reference_type), &
887 : DIMENSION(:), INTENT(OUT), OPTIONAL :: reference
888 :
889 : CHARACTER(len=*), PARAMETER :: routineN = 'init_training_qs_envs'
890 :
891 : CHARACTER(len=default_path_length) :: main_dir, restart_file
892 : CHARACTER(len=default_string_length) :: project_name
893 : INTEGER :: bas_id, handle, icalc, ierr, mp_id, &
894 : n_rep_val, set_id
895 4 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrix_s
896 : TYPE(neighbor_list_set_p_type), DIMENSION(:), &
897 4 : POINTER :: sab_orb
898 : TYPE(qs_environment_type), POINTER :: qs_env, reference_qs_env
899 : TYPE(qs_ks_env_type), POINTER :: ks_env
900 : TYPE(section_vals_type), POINTER :: dft_section, force_env_section, &
901 : input_file, subsys_section
902 :
903 4 : CALL timeset(routineN, handle)
904 :
905 4 : mp_id = opt_bas%opt_id
906 4 : CALL m_getcwd(main_dir)
907 8 : DO icalc = 1, SIZE(opt_bas%comp_group(mp_id)%member_list)
908 4 : NULLIFY (dft_section, force_env_section, input_file, ks_env, matrix_s, qs_env, &
909 4 : reference_qs_env, sab_orb, subsys_section)
910 : CALL get_set_and_basis_id(opt_bas%comp_group(mp_id)%member_list(icalc), opt_bas, &
911 4 : set_id=set_id, bas_id=bas_id)
912 4 : IF (PRESENT(training_input)) THEN
913 2 : CALL section_vals_duplicate(training_input, input_file)
914 : ELSE
915 2 : CALL m_chdir(TRIM(opt_bas%training_dir(set_id)), ierr)
916 2 : IF (ierr /= 0) THEN
917 : CALL cp_abort(__LOCATION__, &
918 0 : "Could not change to directory <"//TRIM(opt_bas%training_dir(set_id))//">")
919 : END IF
920 : input_file => read_input(input_declaration, &
921 : opt_bas%training_input(set_id), &
922 : initial_variables=empty_initial_variables, &
923 2 : para_env=para_env)
924 : CALL check_cp2k_input(input_declaration, input_file, para_env=para_env, &
925 2 : output_unit=-1)
926 : END IF
927 :
928 4 : CALL section_vals_val_set(input_file, "GLOBAL%PRINT_LEVEL", i_val=silent_print_level)
929 4 : IF (PRESENT(reference)) THEN
930 2 : force_env_section => section_vals_get_subs_vals(input_file, "FORCE_EVAL")
931 2 : dft_section => section_vals_get_subs_vals(force_env_section, "DFT")
932 2 : CALL section_vals_val_get(dft_section, "WFN_RESTART_FILE_NAME", n_rep_val=n_rep_val)
933 2 : IF (n_rep_val == 0) THEN
934 2 : CALL section_vals_val_get(input_file, "GLOBAL%PROJECT_NAME", c_val=project_name)
935 2 : restart_file = TRIM(project_name)//"-RESTART.wfn"
936 : CALL section_vals_val_set(dft_section, "WFN_RESTART_FILE_NAME", &
937 2 : c_val=TRIM(restart_file))
938 : END IF
939 2 : CALL section_vals_val_set(dft_section, "SCF%SCF_GUESS", i_val=restart_guess)
940 2 : subsys_section => section_vals_get_subs_vals(force_env_section, "SUBSYS")
941 2 : ALLOCATE (reference_qs_env)
942 2 : CALL qs_env_create(reference_qs_env, globenv)
943 : CALL qs_init(reference_qs_env, para_env, input_file, globenv=globenv, &
944 : force_env_section=force_env_section, subsys_section=subsys_section, &
945 2 : use_motion_section=.TRUE., silent=.TRUE.)
946 2 : CALL allocate_mo_sets(reference_qs_env)
947 2 : CALL get_qs_env(reference_qs_env, ks_env=ks_env)
948 : CALL build_qs_neighbor_lists(reference_qs_env, para_env, molecular=.FALSE., &
949 2 : force_env_section=reference_qs_env%input)
950 2 : CALL get_ks_env(ks_env, matrix_s=matrix_s, sab_orb=sab_orb)
951 : CALL build_overlap_matrix(ks_env, matrix_s=matrix_s, &
952 : matrix_name="OVERLAP", &
953 : basis_type_a="ORB", &
954 : basis_type_b="ORB", &
955 2 : sab_nl=sab_orb)
956 2 : CALL set_ks_env(ks_env, matrix_s=matrix_s)
957 2 : CALL calculate_ks_matrix(reference_qs_env)
958 2 : CALL frontier_orbitals_reference_init(reference_qs_env, reference(icalc))
959 2 : CALL qs_env_release(reference_qs_env)
960 2 : DEALLOCATE (reference_qs_env)
961 : END IF
962 :
963 4 : CALL modify_input_settings(opt_bas, bas_id, input_file)
964 4 : force_env_section => section_vals_get_subs_vals(input_file, "FORCE_EVAL")
965 4 : subsys_section => section_vals_get_subs_vals(force_env_section, "SUBSYS")
966 4 : qs_env => qs_envs(icalc)
967 4 : CALL qs_env_create(qs_env, globenv)
968 : CALL qs_init(qs_env, para_env, input_file, globenv=globenv, &
969 : force_env_section=force_env_section, subsys_section=subsys_section, &
970 4 : use_motion_section=.TRUE., silent=.TRUE.)
971 :
972 4 : CALL section_vals_release(input_file)
973 12 : IF (.NOT. PRESENT(training_input)) CALL m_chdir(TRIM(ADJUSTL(main_dir)), ierr)
974 : END DO
975 :
976 4 : CALL timestop(handle)
977 :
978 4 : END SUBROUTINE init_training_qs_envs
979 :
980 : ! **************************************************************************************************
981 : !> \brief create the force_envs for every input in the computational group
982 : !> \param opt_bas ...
983 : !> \param f_env_id ...
984 : !> \param input_declaration ...
985 : !> \param para_env ...
986 : !> \param mpi_comm_opt ...
987 : !> \param matrix_s_inv ...
988 : !> \param training_input ...
989 : !> \param reference ...
990 : ! **************************************************************************************************
991 :
992 17 : SUBROUTINE init_training_force_envs(opt_bas, f_env_id, input_declaration, para_env, mpi_comm_opt, &
993 4 : matrix_s_inv, training_input, reference)
994 :
995 : TYPE(basis_optimization_type) :: opt_bas
996 : INTEGER, ALLOCATABLE, DIMENSION(:) :: f_env_id
997 : TYPE(section_type), POINTER :: input_declaration
998 : TYPE(mp_para_env_type), POINTER :: para_env
999 : TYPE(mp_comm_type) :: mpi_comm_opt
1000 : TYPE(cp_fm_type), DIMENSION(:), INTENT(OUT), &
1001 : OPTIONAL :: matrix_S_inv
1002 : TYPE(section_vals_type), OPTIONAL, POINTER :: training_input
1003 : TYPE(frontier_orbitals_reference_type), &
1004 : DIMENSION(:), INTENT(OUT), OPTIONAL :: reference
1005 :
1006 : CHARACTER(len=*), PARAMETER :: routineN = 'init_training_force_envs'
1007 :
1008 : CHARACTER(len=default_path_length) :: input_path, main_dir
1009 : INTEGER :: bas_id, f_env_output_unit, handle, &
1010 : icalc, ierr, mp_id, set_id, stat
1011 : TYPE(cp_blacs_env_type), POINTER :: blacs_env
1012 4 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrix_s
1013 : TYPE(f_env_type), POINTER :: f_env
1014 : TYPE(force_env_type), POINTER :: force_env
1015 : TYPE(neighbor_list_set_p_type), DIMENSION(:), &
1016 4 : POINTER :: sab_orb
1017 : TYPE(qs_environment_type), POINTER :: qs_env
1018 : TYPE(qs_ks_env_type), POINTER :: ks_env
1019 : TYPE(section_vals_type), POINTER :: input_file
1020 :
1021 4 : CALL timeset(routineN, handle)
1022 :
1023 4 : NULLIFY (matrix_s, blacs_env, ks_env)
1024 :
1025 4 : mp_id = opt_bas%opt_id
1026 4 : CALL m_getcwd(main_dir)
1027 :
1028 : ! ======= Create f_env for all calculations in MPI group =======
1029 13 : DO icalc = 1, SIZE(opt_bas%comp_group(mp_id)%member_list)
1030 9 : NULLIFY (input_file)
1031 : ! Parse an external training input or duplicate the embedded screening input.
1032 9 : CALL get_set_and_basis_id(opt_bas%comp_group(mp_id)%member_list(icalc), opt_bas, set_id, bas_id)
1033 9 : IF (PRESENT(training_input)) THEN
1034 0 : CALL section_vals_duplicate(training_input, input_file)
1035 0 : input_path = "embedded frontier-orbital screening input"
1036 : ELSE
1037 9 : CALL m_chdir(TRIM(opt_bas%training_dir(set_id)), ierr)
1038 9 : IF (ierr /= 0) THEN
1039 : CALL cp_abort(__LOCATION__, &
1040 0 : "Could not change to directory <"//TRIM(opt_bas%training_dir(set_id))//">")
1041 : END IF
1042 : input_file => read_input(input_declaration, &
1043 : opt_bas%training_input(set_id), &
1044 : initial_variables=empty_initial_variables, &
1045 9 : para_env=para_env)
1046 9 : input_path = opt_bas%training_input(set_id)
1047 : END IF
1048 :
1049 9 : CALL modify_input_settings(opt_bas, bas_id, input_file)
1050 9 : IF (opt_bas%quiet_output .OR. opt_bas%method == method_mo_fit_occ_virtual) THEN
1051 0 : IF (opt_bas%quiet_output) THEN
1052 0 : CALL section_vals_val_set(input_file, "GLOBAL%PRINT_LEVEL", i_val=silent_print_level)
1053 : END IF
1054 0 : f_env_output_unit = -1
1055 0 : IF (para_env%is_source()) f_env_output_unit = cp_logger_get_default_unit_nr()
1056 : CALL create_force_env(f_env_id(icalc), &
1057 : input_declaration=input_declaration, &
1058 : input_path=input_path, &
1059 : input=input_file, &
1060 : output_unit=f_env_output_unit, &
1061 : owns_out_unit=.FALSE., &
1062 : mpi_comm=mpi_comm_opt, &
1063 0 : ierr=stat)
1064 : ELSE
1065 : CALL create_force_env(f_env_id(icalc), &
1066 : input_declaration=input_declaration, &
1067 : input_path=input_path, &
1068 : input=input_file, &
1069 : output_path="scrap_information", &
1070 : mpi_comm=mpi_comm_opt, &
1071 9 : ierr=stat)
1072 : END IF
1073 :
1074 : ! some weirdness with the default stacks defaults have to be addded to get the
1075 : ! correct default program name this causes trouble with the timer stack if kept
1076 9 : CALL f_env_add_defaults(f_env_id(icalc), f_env)
1077 9 : force_env => f_env%force_env
1078 9 : CALL force_env_get(force_env, qs_env=qs_env)
1079 9 : IF (.NOT. PRESENT(training_input)) CALL allocate_mo_sets(qs_env)
1080 9 : CALL f_env_rm_defaults(f_env, stat)
1081 9 : IF (.NOT. PRESENT(training_input)) THEN
1082 9 : CALL get_qs_env(qs_env, ks_env=ks_env)
1083 : CALL build_qs_neighbor_lists(qs_env, para_env, molecular=.FALSE., &
1084 9 : force_env_section=qs_env%input)
1085 : CALL get_ks_env(ks_env, &
1086 : matrix_s=matrix_s, &
1087 9 : sab_orb=sab_orb)
1088 : CALL build_overlap_matrix(ks_env, matrix_s=matrix_s, &
1089 : matrix_name="OVERLAP", &
1090 : basis_type_a="ORB", &
1091 : basis_type_b="ORB", &
1092 9 : sab_nl=sab_orb)
1093 9 : CALL set_ks_env(ks_env, matrix_s=matrix_s)
1094 9 : IF (PRESENT(matrix_s_inv)) THEN
1095 9 : CALL get_qs_env(qs_env, matrix_s=matrix_s, blacs_env=blacs_env)
1096 : CALL calculate_overlap_inverse(matrix_s(1)%matrix, matrix_s_inv(icalc), &
1097 9 : para_env, blacs_env)
1098 : END IF
1099 9 : CALL calculate_ks_matrix(qs_env)
1100 : END IF
1101 9 : IF (opt_bas%method == method_mo_fit_occ_virtual .AND. PRESENT(reference)) THEN
1102 0 : CALL frontier_orbitals_reference_init(qs_env, reference(icalc))
1103 : END IF
1104 :
1105 9 : CALL section_vals_release(input_file)
1106 :
1107 9 : CALL qs_env_part_release(qs_env)
1108 :
1109 22 : IF (.NOT. PRESENT(training_input)) CALL m_chdir(TRIM(ADJUSTL(main_dir)), ierr)
1110 : END DO
1111 :
1112 4 : CALL timestop(handle)
1113 :
1114 4 : END SUBROUTINE init_training_force_envs
1115 :
1116 : ! **************************************************************************************************
1117 : !> \brief variable update from the powell vector for all sets
1118 : !> \param opt_bas ...
1119 : !> \author Florian Schiffmann
1120 : ! **************************************************************************************************
1121 :
1122 530 : SUBROUTINE update_free_vars(opt_bas)
1123 : TYPE(basis_optimization_type) :: opt_bas
1124 :
1125 : CHARACTER(len=*), PARAMETER :: routineN = 'update_free_vars'
1126 :
1127 : INTEGER :: handle, ikind, iset, ix
1128 :
1129 530 : CALL timeset(routineN, handle)
1130 530 : ix = 0
1131 1590 : DO ikind = 1, opt_bas%nkind
1132 2650 : DO iset = 1, opt_bas%kind_basis(ikind)%flex_basis(0)%nsets
1133 2120 : CALL update_subset_freevars(opt_bas%kind_basis(ikind)%flex_basis(0)%subset(iset), ix, opt_bas%x_opt)
1134 : END DO
1135 : END DO
1136 530 : CALL timestop(handle)
1137 :
1138 530 : END SUBROUTINE update_free_vars
1139 :
1140 : ! **************************************************************************************************
1141 : !> \brief low level update for the basis sets. Exponents are transformed according to constraint
1142 : !> \param subset ...
1143 : !> \param ix ...
1144 : !> \param x ...
1145 : !> \author Florian Schiffmann
1146 : ! **************************************************************************************************
1147 :
1148 1060 : SUBROUTINE update_subset_freevars(subset, ix, x)
1149 : TYPE(subset_type) :: subset
1150 : INTEGER :: ix
1151 : REAL(KIND=dp), DIMENSION(:) :: x
1152 :
1153 : CHARACTER(len=*), PARAMETER :: routineN = 'update_subset_freevars'
1154 :
1155 : INTEGER :: handle, icon1, icon2, icont, iexp, il, &
1156 : istart
1157 : REAL(KIND=dp) :: fermi_f, gs_scale
1158 :
1159 1060 : CALL timeset(routineN, handle)
1160 8068 : DO iexp = 1, subset%nexp
1161 7008 : IF (subset%opt_exps(iexp)) THEN
1162 0 : ix = ix + 1
1163 0 : subset%exps(iexp) = ABS(x(ix))
1164 0 : IF (subset%exp_has_const(iexp)) THEN
1165 : !use a fermi function to keep exponents in a given range around their initial value
1166 0 : fermi_f = 1.0_dp/(EXP((x(ix) - 1.0_dp)/0.5_dp) + 1.0_dp)
1167 : subset%exps(iexp) = (2.0_dp*fermi_f - 1.0_dp)*subset%exp_const(iexp)%var_fac*subset%exp_const(iexp)%init + &
1168 0 : subset%exp_const(iexp)%init
1169 : ELSE
1170 :
1171 : END IF
1172 : END IF
1173 41050 : DO icont = 1, subset%ncon_tot
1174 39990 : IF (subset%opt_coeff(iexp, icont)) THEN
1175 16502 : ix = ix + 1
1176 16502 : subset%coeff(iexp, icont) = x(ix)
1177 : END IF
1178 : END DO
1179 : END DO
1180 :
1181 : ! orthonormalize contraction coefficients using gram schmidt
1182 1060 : istart = 1
1183 3710 : DO il = 1, subset%nl
1184 5006 : DO icon1 = istart, istart + subset%l(il) - 2
1185 8128 : DO icon2 = icon1 + 1, istart + subset%l(il) - 1
1186 : gs_scale = DOT_PRODUCT(subset%coeff(:, icon2), subset%coeff(:, icon1))/ &
1187 45182 : DOT_PRODUCT(subset%coeff(:, icon1), subset%coeff(:, icon1))
1188 26508 : subset%coeff(:, icon2) = subset%coeff(:, icon2) - gs_scale*subset%coeff(:, icon1)
1189 : END DO
1190 : END DO
1191 3710 : istart = istart + subset%l(il)
1192 : END DO
1193 :
1194 6066 : DO icon1 = 1, subset%ncon_tot
1195 72030 : subset%coeff(:, icon1) = subset%coeff(:, icon1)/NORM2(subset%coeff(:, icon1))
1196 : END DO
1197 1060 : CALL timestop(handle)
1198 :
1199 1060 : END SUBROUTINE update_subset_freevars
1200 :
1201 : ! **************************************************************************************************
1202 : !> \brief variable initialization for the powell vector for all sets
1203 : !> \param opt_bas ...
1204 : !> \author Florian Schiffmann
1205 : ! **************************************************************************************************
1206 :
1207 12 : SUBROUTINE init_free_vars(opt_bas)
1208 : TYPE(basis_optimization_type) :: opt_bas
1209 :
1210 : CHARACTER(len=*), PARAMETER :: routineN = 'init_free_vars'
1211 :
1212 : INTEGER :: handle, ikind, iset, ix
1213 :
1214 12 : CALL timeset(routineN, handle)
1215 12 : ix = 0
1216 36 : DO ikind = 1, opt_bas%nkind
1217 60 : DO iset = 1, opt_bas%kind_basis(ikind)%flex_basis(0)%nsets
1218 48 : CALL init_subset_freevars(opt_bas%kind_basis(ikind)%flex_basis(0)%subset(iset), ix, opt_bas%x_opt)
1219 : END DO
1220 : END DO
1221 12 : CALL timestop(handle)
1222 :
1223 12 : END SUBROUTINE init_free_vars
1224 :
1225 : ! **************************************************************************************************
1226 : !> \brief variable initialization for the powell vector from low level informations
1227 : !> constraint exponents will be mapped on a fermi function
1228 : !> \param subset ...
1229 : !> \param ix ...
1230 : !> \param x ...
1231 : !> \author Florian Schiffmann
1232 : ! **************************************************************************************************
1233 :
1234 24 : SUBROUTINE init_subset_freevars(subset, ix, x)
1235 : TYPE(subset_type) :: subset
1236 : INTEGER :: ix
1237 : REAL(KIND=dp), DIMENSION(:) :: x
1238 :
1239 : CHARACTER(len=*), PARAMETER :: routineN = 'init_subset_freevars'
1240 :
1241 : INTEGER :: handle, icont, iexp
1242 : REAL(KIND=dp) :: fract
1243 :
1244 24 : CALL timeset(routineN, handle)
1245 :
1246 184 : DO iexp = 1, subset%nexp
1247 160 : IF (subset%opt_exps(iexp)) THEN
1248 0 : ix = ix + 1
1249 0 : x(ix) = subset%exps(iexp)
1250 0 : IF (subset%exp_has_const(iexp)) THEN
1251 0 : IF (subset%exp_const(iexp)%const_type == 0) THEN
1252 : fract = 1.0_dp + (subset%exps(iexp) - subset%exp_const(iexp)%init)/ &
1253 0 : (subset%exp_const(iexp)%init*subset%exp_const(iexp)%var_fac)
1254 0 : x(ix) = 0.5_dp*LOG((2.0_dp/fract - 1.0_dp)) + 1.0_dp
1255 : END IF
1256 0 : IF (subset%exp_const(iexp)%const_type == 1) THEN
1257 0 : x(ix) = 1.0_dp
1258 : END IF
1259 : END IF
1260 : END IF
1261 956 : DO icont = 1, subset%ncon_tot
1262 932 : IF (subset%opt_coeff(iexp, icont)) THEN
1263 452 : ix = ix + 1
1264 452 : x(ix) = subset%coeff(iexp, icont)
1265 : END IF
1266 : END DO
1267 : END DO
1268 24 : CALL timestop(handle)
1269 :
1270 24 : END SUBROUTINE init_subset_freevars
1271 :
1272 : ! **************************************************************************************************
1273 : !> \brief commuticates all info to the master and assembles the output
1274 : !> \param f_vec ...
1275 : !> \param cond_vec ...
1276 : !> \param my_time ...
1277 : !> \param tot_time ...
1278 : !> \param opt_bas ...
1279 : !> \param iopt ...
1280 : !> \param para_env_top ...
1281 : !> \author Florian Schiffmann
1282 : ! **************************************************************************************************
1283 :
1284 114 : SUBROUTINE output_opt_info(f_vec, cond_vec, my_time, tot_time, opt_bas, iopt, para_env_top)
1285 : REAL(KIND=dp), DIMENSION(:) :: f_vec, cond_vec, my_time, tot_time
1286 : TYPE(basis_optimization_type) :: opt_bas
1287 : INTEGER :: iopt
1288 : TYPE(mp_para_env_type), POINTER :: para_env_top
1289 :
1290 : CHARACTER(len=*), PARAMETER :: routineN = 'output_opt_info'
1291 :
1292 : INTEGER :: handle, ibasis, icalc, iset, unit_nr
1293 : TYPE(cp_logger_type), POINTER :: logger
1294 :
1295 114 : CALL timeset(routineN, handle)
1296 114 : logger => cp_get_default_logger()
1297 :
1298 582 : tot_time = tot_time + my_time
1299 :
1300 114 : unit_nr = -1
1301 114 : IF (para_env_top%is_source() .AND. (MOD(iopt, opt_bas%write_frequency) == 0 .OR. iopt == opt_bas%powell_param%maxfun)) THEN
1302 5 : unit_nr = cp_logger_get_default_unit_nr(logger)
1303 : END IF
1304 :
1305 5 : IF (unit_nr > 0) THEN
1306 5 : WRITE (unit_nr, '(1X,A,I8)') "BASOPT| Information at iteration number:", iopt
1307 5 : WRITE (unit_nr, '(1X,A)') "BASOPT| Training set | Combination | Rho difference | Condition num. | Time"
1308 5 : WRITE (unit_nr, '(1X,A)') "BASOPT| -----------------------------------------------------------------------"
1309 5 : icalc = 0
1310 12 : DO iset = 1, opt_bas%ntraining_sets
1311 33 : DO ibasis = 1, opt_bas%ncombinations
1312 21 : icalc = icalc + 1
1313 : WRITE (unit_nr, '(1X,A,2(5X,I3,5X,A),2(1X,E14.8,1X,A),1X,F8.1)') &
1314 28 : 'BASOPT| ', iset, "|", ibasis, "|", f_vec(icalc), "|", cond_vec(icalc), "|", tot_time(icalc)
1315 : END DO
1316 : END DO
1317 5 : WRITE (unit_nr, '(1X,A)') "BASOPT| -----------------------------------------------------------------------"
1318 5 : WRITE (unit_nr, '(1X,A,E14.8)') "BASOPT| Total residuum value: ", opt_bas%powell_param%f
1319 5 : WRITE (unit_nr, '(A)') ""
1320 : END IF
1321 114 : CALL timestop(handle)
1322 114 : END SUBROUTINE output_opt_info
1323 :
1324 : END MODULE optimize_basis
|