Line data Source code
1 : !--------------------------------------------------------------------------------------------------!
2 : ! CP2K: A general program to perform molecular dynamics simulations !
3 : ! Copyright 2000-2024 CP2K developers group <https://cp2k.org> !
4 : ! !
5 : ! SPDX-License-Identifier: GPL-2.0-or-later !
6 : !--------------------------------------------------------------------------------------------------!
7 : MODULE optimize_basis_utils
8 : USE cp_files, ONLY: close_file,&
9 : open_file
10 : USE cp_log_handling, ONLY: cp_get_default_logger,&
11 : cp_logger_get_default_unit_nr,&
12 : cp_logger_type,&
13 : cp_to_string
14 : USE cp_parser_methods, ONLY: parser_get_object,&
15 : parser_search_string
16 : USE cp_parser_types, ONLY: cp_parser_type,&
17 : parser_create,&
18 : parser_release
19 : USE input_constants, ONLY: do_opt_all,&
20 : do_opt_coeff,&
21 : do_opt_exps,&
22 : do_opt_none
23 : USE input_section_types, ONLY: section_vals_get,&
24 : section_vals_get_subs_vals,&
25 : section_vals_type,&
26 : section_vals_val_get
27 : USE kinds, ONLY: default_path_length,&
28 : default_string_length,&
29 : dp
30 : USE machine, ONLY: default_output_unit,&
31 : m_getcwd
32 : USE message_passing, ONLY: mp_para_env_type
33 : USE optimize_basis_types, ONLY: basis_optimization_type,&
34 : derived_basis_info,&
35 : flex_basis_type,&
36 : subset_type
37 : USE powell, ONLY: opt_state_type
38 : USE string_utilities, ONLY: uppercase
39 : #include "./base/base_uses.f90"
40 :
41 : IMPLICIT NONE
42 : PRIVATE
43 :
44 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'optimize_basis_utils'
45 :
46 : PUBLIC :: optimize_basis_init_read_input, get_set_and_basis_id, &
47 : update_derived_basis_sets
48 :
49 : CONTAINS
50 :
51 : ! **************************************************************************************************
52 : !> \brief initialize all parts of the optimization type and read input settings
53 : !> \param opt_bas ...
54 : !> \param root_section ...
55 : !> \param para_env ...
56 : !> \author Florian Schiffmann
57 : ! **************************************************************************************************
58 :
59 4 : SUBROUTINE optimize_basis_init_read_input(opt_bas, root_section, para_env)
60 : TYPE(basis_optimization_type) :: opt_bas
61 : TYPE(section_vals_type), POINTER :: root_section
62 : TYPE(mp_para_env_type), POINTER :: para_env
63 :
64 : CHARACTER(LEN=default_path_length) :: main_dir
65 : INTEGER :: iset, iweight, nrep
66 : TYPE(section_vals_type), POINTER :: kind_section, optbas_section, &
67 : powell_section, train_section
68 :
69 4 : optbas_section => section_vals_get_subs_vals(root_section, "OPTIMIZE_BASIS")
70 4 : powell_section => section_vals_get_subs_vals(optbas_section, "OPTIMIZATION")
71 4 : train_section => section_vals_get_subs_vals(optbas_section, "TRAINING_FILES")
72 4 : kind_section => section_vals_get_subs_vals(optbas_section, "FIT_KIND")
73 :
74 4 : CALL section_vals_val_get(optbas_section, "BASIS_TEMPLATE_FILE", c_val=opt_bas%template_basis_file)
75 4 : CALL section_vals_val_get(optbas_section, "BASIS_WORK_FILE", c_val=opt_bas%work_basis_file)
76 4 : CALL section_vals_val_get(optbas_section, "BASIS_OUTPUT_FILE", c_val=opt_bas%output_basis_file)
77 4 : CALL m_getcwd(main_dir)
78 4 : opt_bas%work_basis_file = TRIM(ADJUSTL(main_dir))//"/"//TRIM(ADJUSTL(opt_bas%work_basis_file))
79 :
80 4 : CALL section_vals_val_get(optbas_section, "WRITE_FREQUENCY", i_val=opt_bas%write_frequency)
81 4 : CALL section_vals_val_get(optbas_section, "USE_CONDITION_NUMBER", l_val=opt_bas%use_condition_number)
82 :
83 4 : CALL generate_initial_basis(kind_section, opt_bas, para_env)
84 :
85 4 : CALL section_vals_get(train_section, n_repetition=opt_bas%ntraining_sets)
86 4 : IF (opt_bas%ntraining_sets == 0) &
87 0 : CPABORT("No training set was specified in the Input")
88 :
89 12 : ALLOCATE (opt_bas%training_input(opt_bas%ntraining_sets))
90 12 : ALLOCATE (opt_bas%training_dir(opt_bas%ntraining_sets))
91 10 : DO iset = 1, opt_bas%ntraining_sets
92 : CALL section_vals_val_get(train_section, "DIRECTORY", c_val=opt_bas%training_dir(iset), &
93 6 : i_rep_section=iset)
94 : CALL section_vals_val_get(train_section, "INPUT_FILE_NAME", c_val=opt_bas%training_input(iset), &
95 10 : i_rep_section=iset)
96 : END DO
97 :
98 4 : CALL init_powell_var(opt_bas%powell_param, powell_section)
99 4 : opt_bas%powell_param%nvar = SIZE(opt_bas%x_opt)
100 :
101 4 : CALL generate_derived_basis_sets(opt_bas, para_env)
102 :
103 4 : CALL generate_basis_combinations(opt_bas, optbas_section)
104 :
105 4 : CALL section_vals_val_get(optbas_section, "RESIDUUM_WEIGHT", n_rep_val=nrep)
106 12 : ALLOCATE (opt_bas%fval_weight(0:opt_bas%ncombinations))
107 20 : opt_bas%fval_weight = 1.0_dp
108 16 : DO iweight = 1, nrep
109 : CALL section_vals_val_get(optbas_section, "RESIDUUM_WEIGHT", r_val=opt_bas%fval_weight(iweight - 1), &
110 16 : i_rep_val=iweight)
111 : END DO
112 :
113 4 : CALL section_vals_val_get(optbas_section, "CONDITION_WEIGHT", n_rep_val=nrep)
114 12 : ALLOCATE (opt_bas%condition_weight(0:opt_bas%ncombinations))
115 20 : opt_bas%condition_weight = 1.0_dp
116 16 : DO iweight = 1, nrep
117 : CALL section_vals_val_get(optbas_section, "CONDITION_WEIGHT", r_val=opt_bas%condition_weight(iweight - 1), &
118 16 : i_rep_val=iweight)
119 : END DO
120 :
121 4 : CALL generate_computation_groups(opt_bas, optbas_section, para_env)
122 :
123 4 : CALL print_opt_info(opt_bas)
124 :
125 8 : END SUBROUTINE optimize_basis_init_read_input
126 :
127 : ! **************************************************************************************************
128 : !> \brief ...
129 : !> \param opt_bas ...
130 : ! **************************************************************************************************
131 4 : SUBROUTINE print_opt_info(opt_bas)
132 : TYPE(basis_optimization_type) :: opt_bas
133 :
134 : INTEGER :: icomb, ikind, unit_nr
135 : TYPE(cp_logger_type), POINTER :: logger
136 :
137 4 : logger => cp_get_default_logger()
138 4 : unit_nr = -1
139 4 : IF (logger%para_env%is_source()) &
140 2 : unit_nr = cp_logger_get_default_unit_nr(logger)
141 :
142 2 : IF (unit_nr > 0) THEN
143 2 : WRITE (unit_nr, '(1X,A,A)') "BASOPT| Total number of calculations ", &
144 4 : TRIM(cp_to_string(opt_bas%ncombinations*opt_bas%ntraining_sets))
145 2 : WRITE (unit_nr, '(A)') ""
146 8 : DO icomb = 1, opt_bas%ncombinations
147 6 : WRITE (unit_nr, '(1X,A,A)') "BASOPT| Content of basis combination ", TRIM(cp_to_string(icomb))
148 18 : DO ikind = 1, opt_bas%nkind
149 12 : WRITE (unit_nr, '(1X,A,A4,4X,A,3X,A)') "BASOPT| Element: ", TRIM(opt_bas%kind_basis(ikind)%element), &
150 30 : "Basis set: ", TRIM(opt_bas%kind_basis(ikind)%flex_basis(opt_bas%combination(icomb, ikind))%basis_name)
151 : END DO
152 8 : WRITE (unit_nr, '(A)') ""
153 : END DO
154 : END IF
155 4 : END SUBROUTINE print_opt_info
156 :
157 : ! **************************************************************************************************
158 : !> \brief Generation of the requested basis set combinations if multiple kinds
159 : !> are fitted at the same time (if not specified create all possible)
160 : !> \param opt_bas ...
161 : !> \param optbas_section ...
162 : !> \author Florian Schiffmann
163 : ! **************************************************************************************************
164 4 : SUBROUTINE generate_basis_combinations(opt_bas, optbas_section)
165 : TYPE(basis_optimization_type) :: opt_bas
166 : TYPE(section_vals_type), POINTER :: optbas_section
167 :
168 : INTEGER :: i, ikind, j, n_rep
169 4 : INTEGER, DIMENSION(:), POINTER :: i_vals, tmp_i, tmp_i2
170 : LOGICAL :: explicit, raise
171 :
172 : !setup the basis combinations to optimize
173 :
174 4 : CALL section_vals_val_get(optbas_section, "BASIS_COMBINATIONS", explicit=explicit, n_rep_val=n_rep)
175 4 : IF (.NOT. explicit) THEN
176 0 : opt_bas%ncombinations = 1
177 0 : ALLOCATE (tmp_i(opt_bas%nkind))
178 0 : ALLOCATE (tmp_i2(opt_bas%nkind))
179 0 : DO ikind = 1, opt_bas%nkind
180 0 : opt_bas%ncombinations = opt_bas%ncombinations*SIZE(opt_bas%kind_basis(ikind)%flex_basis)
181 0 : tmp_i(ikind) = opt_bas%kind_basis(ikind)%nbasis_deriv
182 : END DO
183 0 : ALLOCATE (opt_bas%combination(opt_bas%ncombinations, opt_bas%nkind))
184 0 : tmp_i2 = 0
185 0 : DO i = 1, opt_bas%ncombinations
186 0 : DO j = 1, opt_bas%nkind
187 0 : opt_bas%combination(i, j) = tmp_i2(j)
188 : END DO
189 0 : tmp_i2(opt_bas%nkind) = tmp_i2(opt_bas%nkind) + 1
190 0 : raise = .FALSE.
191 0 : DO j = opt_bas%nkind, 1, -1
192 0 : IF (raise) tmp_i2(j) = tmp_i2(j) + 1
193 0 : IF (tmp_i2(j) .GT. tmp_i(j)) THEN
194 0 : tmp_i2(j) = 0
195 0 : raise = .TRUE.
196 : END IF
197 : END DO
198 : END DO
199 0 : DEALLOCATE (tmp_i)
200 0 : DEALLOCATE (tmp_i2)
201 : ELSE
202 4 : opt_bas%ncombinations = n_rep
203 16 : ALLOCATE (opt_bas%combination(opt_bas%ncombinations, opt_bas%nkind))
204 16 : DO i = 1, n_rep
205 12 : CALL section_vals_val_get(optbas_section, "BASIS_COMBINATIONS", i_vals=i_vals, i_rep_val=i)
206 40 : opt_bas%combination(i, :) = i_vals(:)
207 : END DO
208 : END IF
209 :
210 4 : END SUBROUTINE generate_basis_combinations
211 :
212 : ! **************************************************************************************************
213 : !> \brief returns a mapping from the calculation id to the trainings set id and
214 : !> basis combination id
215 : !> \param calc_id ...
216 : !> \param opt_bas ...
217 : !> \param set_id ...
218 : !> \param bas_id ...
219 : !> \author Florian Schiffmann
220 : ! **************************************************************************************************
221 :
222 243 : SUBROUTINE get_set_and_basis_id(calc_id, opt_bas, set_id, bas_id)
223 :
224 : INTEGER :: calc_id
225 : TYPE(basis_optimization_type) :: opt_bas
226 : INTEGER :: set_id, bas_id
227 :
228 : INTEGER :: ncom, nset
229 :
230 243 : ncom = opt_bas%ncombinations
231 243 : nset = opt_bas%ntraining_sets
232 :
233 243 : set_id = (calc_id)/ncom + 1
234 243 : bas_id = MOD(calc_id, ncom) + 1
235 :
236 243 : END SUBROUTINE
237 :
238 : ! **************************************************************************************************
239 : !> \brief Pack calculations in groups. If less MPI tasks than systems are used
240 : !> multiple systems will be assigned to a single MPI task
241 : !> \param opt_bas ...
242 : !> \param optbas_section ...
243 : !> \param para_env ...
244 : !> \author Florian Schiffmann
245 : ! **************************************************************************************************
246 :
247 4 : SUBROUTINE generate_computation_groups(opt_bas, optbas_section, para_env)
248 : TYPE(basis_optimization_type) :: opt_bas
249 : TYPE(section_vals_type), POINTER :: optbas_section
250 : TYPE(mp_para_env_type), POINTER :: para_env
251 :
252 : INTEGER :: iadd1, iadd2, icount, igroup, isize, j, &
253 : ncalc, nproc, nptot
254 4 : INTEGER, DIMENSION(:), POINTER :: i_vals
255 : LOGICAL :: explicit
256 :
257 4 : nproc = para_env%num_pe
258 4 : ncalc = opt_bas%ncombinations*opt_bas%ntraining_sets
259 4 : CALL section_vals_val_get(optbas_section, "GROUP_PARTITION", explicit=explicit)
260 :
261 : ! No input information available, try to equally distribute
262 4 : IF (.NOT. explicit) THEN
263 4 : IF (nproc .GE. ncalc) THEN
264 0 : iadd1 = nproc/ncalc
265 0 : iadd2 = MOD(nproc, ncalc)
266 0 : ALLOCATE (opt_bas%comp_group(ncalc))
267 0 : ALLOCATE (opt_bas%group_partition(0:ncalc - 1))
268 0 : DO igroup = 0, ncalc - 1
269 0 : ALLOCATE (opt_bas%comp_group(igroup + 1)%member_list(1))
270 0 : opt_bas%comp_group(igroup + 1)%member_list(1) = igroup
271 0 : opt_bas%group_partition(igroup) = iadd1
272 0 : IF (igroup .LT. iadd2) opt_bas%group_partition(igroup) = opt_bas%group_partition(igroup) + 1
273 : END DO
274 : ELSE
275 4 : iadd1 = ncalc/nproc
276 4 : iadd2 = MOD(ncalc, nproc)
277 20 : ALLOCATE (opt_bas%comp_group(nproc))
278 12 : ALLOCATE (opt_bas%group_partition(0:nproc - 1))
279 4 : icount = 0
280 12 : DO igroup = 0, nproc - 1
281 8 : opt_bas%group_partition(igroup) = 1
282 8 : isize = iadd1
283 8 : IF (igroup .LT. iadd2) isize = isize + 1
284 24 : ALLOCATE (opt_bas%comp_group(igroup + 1)%member_list(isize))
285 30 : DO j = 1, isize
286 18 : opt_bas%comp_group(igroup + 1)%member_list(j) = icount
287 26 : icount = icount + 1
288 : END DO
289 : END DO
290 : END IF
291 : ELSE
292 :
293 : ! Group partition from input. see if all systems can be assigned. If not add to existing group
294 0 : CALL section_vals_val_get(optbas_section, "GROUP_PARTITION", i_vals=i_vals)
295 0 : isize = SIZE(i_vals)
296 0 : nptot = SUM(i_vals)
297 0 : IF (nptot /= nproc) &
298 : CALL cp_abort(__LOCATION__, &
299 : "Number of processors in group distribution does not match number of MPI tasks."// &
300 0 : " Please change input.")
301 0 : IF (.NOT. isize .LE. ncalc) &
302 : CALL cp_abort(__LOCATION__, &
303 : "Number of Groups larger than number of calculations"// &
304 0 : " Please change input.")
305 0 : CPASSERT(nptot == nproc)
306 0 : ALLOCATE (opt_bas%comp_group(isize))
307 0 : ALLOCATE (opt_bas%group_partition(0:isize - 1))
308 0 : IF (isize .LT. ncalc) THEN
309 0 : iadd1 = ncalc/isize
310 0 : iadd2 = MOD(ncalc, isize)
311 0 : icount = 0
312 0 : DO igroup = 0, isize - 1
313 0 : opt_bas%group_partition(igroup) = i_vals(igroup + 1)
314 0 : isize = iadd1
315 0 : IF (igroup .LT. iadd2) isize = isize + 1
316 0 : ALLOCATE (opt_bas%comp_group(igroup + 1)%member_list(isize))
317 0 : DO j = 1, isize
318 0 : opt_bas%comp_group(igroup + 1)%member_list(j) = icount
319 0 : icount = icount + 1
320 : END DO
321 : END DO
322 : ELSE
323 0 : DO igroup = 0, isize - 1
324 0 : opt_bas%group_partition(igroup) = i_vals(igroup + 1)
325 0 : ALLOCATE (opt_bas%comp_group(igroup + 1)%member_list(1))
326 0 : opt_bas%comp_group(igroup + 1)%member_list(1) = igroup
327 : END DO
328 : END IF
329 : END IF
330 :
331 4 : END SUBROUTINE generate_computation_groups
332 :
333 : ! **************************************************************************************************
334 : !> \brief Regenerate the basis sets from reference 0 after an update from the
335 : !> optimizer to reference was performed, and print basis file if required
336 : !> \param opt_bas ...
337 : !> \param write_it ...
338 : !> \param output_file ...
339 : !> \param para_env ...
340 : !> \author Florian Schiffmann
341 : ! **************************************************************************************************
342 118 : SUBROUTINE update_derived_basis_sets(opt_bas, write_it, output_file, para_env)
343 : TYPE(basis_optimization_type) :: opt_bas
344 : LOGICAL :: write_it
345 : CHARACTER(LEN=default_path_length) :: output_file
346 : TYPE(mp_para_env_type), POINTER :: para_env
347 :
348 : INTEGER :: ibasis, ikind, unit_nr
349 :
350 354 : DO ikind = 1, opt_bas%nkind
351 826 : DO ibasis = 1, opt_bas%kind_basis(ikind)%nbasis_deriv
352 : CALL update_used_parts(opt_bas%kind_basis(ikind)%deriv_info(ibasis), &
353 : opt_bas%kind_basis(ikind)%flex_basis(0), &
354 708 : opt_bas%kind_basis(ikind)%flex_basis(ibasis))
355 : END DO
356 : END DO
357 :
358 118 : IF (write_it) THEN
359 12 : IF (para_env%is_source()) THEN
360 : CALL open_file(file_name=output_file, file_status="UNKNOWN", &
361 6 : file_action="WRITE", unit_number=unit_nr)
362 : ELSE
363 6 : unit_nr = -999
364 : END IF
365 36 : DO ikind = 1, opt_bas%nkind
366 108 : DO ibasis = 0, opt_bas%kind_basis(ikind)%nbasis_deriv
367 : CALL write_basis(opt_bas%kind_basis(ikind)%flex_basis(ibasis), opt_bas%kind_basis(ikind)%element, &
368 96 : unit_nr)
369 : END DO
370 : END DO
371 12 : IF (para_env%is_source()) CALL close_file(unit_number=unit_nr)
372 : END IF
373 :
374 118 : END SUBROUTINE update_derived_basis_sets
375 :
376 : ! **************************************************************************************************
377 : !> \brief Update the the information in a given basis set
378 : !> \param info_new ...
379 : !> \param basis ...
380 : !> \param basis_new ...
381 : !> \author Florian Schiffmann
382 : ! **************************************************************************************************
383 :
384 472 : SUBROUTINE update_used_parts(info_new, basis, basis_new)
385 : TYPE(derived_basis_info) :: info_new
386 : TYPE(flex_basis_type) :: basis, basis_new
387 :
388 : INTEGER :: icont, iset, jcont, jset
389 :
390 472 : jset = 0
391 944 : DO iset = 1, basis%nsets
392 944 : IF (info_new%in_use_set(iset)) THEN
393 472 : jset = jset + 1
394 3776 : basis_new%subset(jset)%exps(:) = basis%subset(iset)%exps
395 472 : jcont = 0
396 3068 : DO icont = 1, basis%subset(iset)%ncon_tot
397 3068 : IF (info_new%use_contr(iset)%in_use(icont)) THEN
398 1298 : jcont = jcont + 1
399 10384 : basis_new%subset(jset)%coeff(:, jcont) = basis%subset(iset)%coeff(:, icont)
400 : END IF
401 : END DO
402 : END IF
403 : END DO
404 :
405 472 : END SUBROUTINE update_used_parts
406 :
407 : ! **************************************************************************************************
408 : !> \brief Initial generation of the basis set from the file and DERIVED_SET
409 : !> \param opt_bas ...
410 : !> \param para_env ...
411 : !> \author Florian Schiffmann
412 : ! **************************************************************************************************
413 :
414 4 : SUBROUTINE generate_derived_basis_sets(opt_bas, para_env)
415 : TYPE(basis_optimization_type) :: opt_bas
416 : TYPE(mp_para_env_type), POINTER :: para_env
417 :
418 : INTEGER :: ibasis, ikind, iref, jbasis, unit_nr
419 :
420 12 : DO ikind = 1, opt_bas%nkind
421 8 : CALL init_deriv_info_ref(opt_bas%kind_basis(ikind)%deriv_info(0), opt_bas%kind_basis(ikind)%flex_basis(0))
422 8 : opt_bas%kind_basis(ikind)%deriv_info(0)%basis_name = TRIM(ADJUSTL(opt_bas%kind_basis(ikind)%basis_name))
423 : ! initialize the reference set used as template for the rest
424 28 : DO ibasis = 1, opt_bas%kind_basis(ikind)%nbasis_deriv
425 16 : iref = opt_bas%kind_basis(ikind)%deriv_info(ibasis)%reference_set
426 72 : DO jbasis = 0, opt_bas%kind_basis(ikind)%nbasis_deriv
427 48 : IF (iref == jbasis) CALL setup_used_parts_init_basis(opt_bas%kind_basis(ikind)%deriv_info(ibasis), &
428 : opt_bas%kind_basis(ikind)%deriv_info(iref), &
429 : opt_bas%kind_basis(ikind)%flex_basis(0), &
430 32 : opt_bas%kind_basis(ikind)%flex_basis(ibasis))
431 : END DO
432 : END DO
433 : END DO
434 :
435 4 : IF (para_env%is_source()) THEN
436 : CALL open_file(file_name=opt_bas%work_basis_file, file_status="UNKNOWN", &
437 2 : file_action="WRITE", unit_number=unit_nr)
438 : ELSE
439 2 : unit_nr = -999
440 : END IF
441 12 : DO ikind = 1, opt_bas%nkind
442 36 : DO ibasis = 0, opt_bas%kind_basis(ikind)%nbasis_deriv
443 24 : IF (LEN_TRIM(opt_bas%kind_basis(ikind)%deriv_info(ibasis)%basis_name) > 0) THEN
444 : opt_bas%kind_basis(ikind)%flex_basis(ibasis)%basis_name = &
445 16 : TRIM(ADJUSTL(opt_bas%kind_basis(ikind)%deriv_info(ibasis)%basis_name))
446 : ELSE
447 : opt_bas%kind_basis(ikind)%flex_basis(ibasis)%basis_name = &
448 8 : TRIM(ADJUSTL(opt_bas%kind_basis(ikind)%basis_name))//"-DERIVED_SET-"//ADJUSTL(cp_to_string(ibasis))
449 : END IF
450 : CALL write_basis(opt_bas%kind_basis(ikind)%flex_basis(ibasis), opt_bas%kind_basis(ikind)%element, &
451 32 : unit_nr)
452 : END DO
453 : END DO
454 4 : IF (para_env%is_source()) CALL close_file(unit_number=unit_nr)
455 :
456 4 : END SUBROUTINE generate_derived_basis_sets
457 :
458 : ! **************************************************************************************************
459 : !> \brief Write a basis set file which can be used from CP2K
460 : !> \param basis ...
461 : !> \param element ...
462 : !> \param unit_nr ...
463 : !> \author Florian Schiffmann
464 : ! **************************************************************************************************
465 :
466 96 : SUBROUTINE write_basis(basis, element, unit_nr)
467 : TYPE(flex_basis_type) :: basis
468 : CHARACTER(LEN=default_string_length) :: element
469 : INTEGER :: unit_nr
470 :
471 : INTEGER :: iexp, iset
472 :
473 96 : IF (unit_nr > 0) THEN
474 48 : WRITE (UNIT=unit_nr, FMT="(A)") TRIM(ADJUSTL(element))//" "//TRIM(ADJUSTL(basis%basis_name))
475 48 : WRITE (UNIT=unit_nr, FMT="(1X,I0)") basis%nsets
476 96 : DO iset = 1, basis%nsets
477 48 : WRITE (UNIT=unit_nr, FMT="(30(1X,I0))") basis%subset(iset)%n, basis%subset(iset)%lmin, basis%subset(iset)%lmax, &
478 200 : basis%subset(iset)%nexp, basis%subset(iset)%l
479 432 : DO iexp = 1, basis%subset(iset)%nexp
480 : WRITE (UNIT=unit_nr, FMT="(T2,F24.14,30(1X,ES24.14))") &
481 1616 : basis%subset(iset)%exps(iexp), basis%subset(iset)%coeff(iexp, :)
482 : END DO
483 : END DO
484 : END IF
485 :
486 96 : END SUBROUTINE write_basis
487 :
488 : ! **************************************************************************************************
489 : !> \brief Initialize the derived basis sets and the vectors containing their
490 : !> assembly information ehich is used for regeneration of the sets.
491 : !> \param info_new ...
492 : !> \param info_ref ...
493 : !> \param basis ...
494 : !> \param basis_new ...
495 : !> \author Florian Schiffmann
496 : ! **************************************************************************************************
497 :
498 16 : SUBROUTINE setup_used_parts_init_basis(info_new, info_ref, basis, basis_new)
499 : TYPE(derived_basis_info) :: info_new, info_ref
500 : TYPE(flex_basis_type) :: basis, basis_new
501 :
502 : INTEGER :: i, jset, lind, nsets
503 :
504 : ! copy the reference information on the new set
505 :
506 48 : ALLOCATE (info_new%in_use_set(SIZE(info_ref%in_use_set)))
507 32 : info_new%in_use_set(:) = info_ref%in_use_set
508 64 : ALLOCATE (info_new%use_contr(SIZE(info_ref%in_use_set)))
509 32 : DO i = 1, SIZE(info_ref%in_use_set)
510 48 : ALLOCATE (info_new%use_contr(i)%in_use(SIZE(info_ref%use_contr(i)%in_use)))
511 120 : info_new%use_contr(i)%in_use(:) = info_ref%use_contr(i)%in_use
512 : END DO
513 16 : DO i = 1, info_new%nsets
514 16 : info_new%in_use_set(info_new%remove_set(i)) = .FALSE.
515 : END DO
516 48 : DO i = 1, info_new%ncontr
517 : lind = convert_l_contr_to_entry(basis%subset(info_new%remove_contr(i, 1))%lmin, &
518 : basis%subset(info_new%remove_contr(i, 1))%l, &
519 32 : info_new%remove_contr(i, 3), info_new%remove_contr(i, 2))
520 :
521 48 : info_new%use_contr(info_new%remove_contr(i, 1))%in_use(lind) = .FALSE.
522 : END DO
523 :
524 16 : nsets = 0
525 32 : DO i = 1, basis%nsets
526 32 : IF (info_new%in_use_set(i)) nsets = nsets + 1
527 : END DO
528 16 : basis_new%nsets = nsets
529 64 : ALLOCATE (basis_new%subset(nsets))
530 16 : jset = 0
531 32 : DO i = 1, basis%nsets
532 32 : IF (info_new%in_use_set(i)) THEN
533 16 : jset = jset + 1
534 16 : CALL create_new_subset(basis%subset(i), basis_new%subset(jset), info_new%use_contr(jset)%in_use)
535 : END IF
536 : END DO
537 :
538 16 : END SUBROUTINE setup_used_parts_init_basis
539 :
540 : ! **************************************************************************************************
541 : !> \brief Fill the low level information of the derived basis set.
542 : !> \param subset ...
543 : !> \param subset_new ...
544 : !> \param in_use ...
545 : !> \author Florian Schiffmann
546 : ! **************************************************************************************************
547 :
548 16 : SUBROUTINE create_new_subset(subset, subset_new, in_use)
549 : TYPE(subset_type) :: subset, subset_new
550 : LOGICAL, DIMENSION(:) :: in_use
551 :
552 : INTEGER :: icon, iind, il
553 16 : INTEGER, ALLOCATABLE, DIMENSION(:) :: tmp_l
554 :
555 48 : ALLOCATE (tmp_l(SIZE(subset%l)))
556 56 : tmp_l(:) = subset%l
557 16 : subset_new%lmin = subset%lmin
558 16 : subset_new%lmax = subset%lmin - 1
559 16 : subset_new%nexp = subset%nexp
560 16 : subset_new%n = subset%n
561 56 : DO il = 1, SIZE(subset%l)
562 128 : DO icon = 1, subset%l(il)
563 88 : iind = convert_l_contr_to_entry(subset%lmin, subset%l, icon, subset%lmin + il - 1)
564 128 : IF (.NOT. in_use(iind)) tmp_l(il) = tmp_l(il) - 1
565 : END DO
566 56 : IF (tmp_l(il) .GT. 0) subset_new%lmax = subset_new%lmax + 1
567 : END DO
568 16 : subset_new%nl = subset_new%lmax - subset_new%lmin + 1
569 56 : subset_new%ncon_tot = SUM(tmp_l)
570 48 : ALLOCATE (subset_new%l(subset_new%nl))
571 64 : ALLOCATE (subset_new%coeff(subset_new%nexp, subset_new%ncon_tot))
572 48 : ALLOCATE (subset_new%exps(subset_new%nexp))
573 128 : subset_new%exps(:) = subset%exps
574 48 : DO il = 1, SIZE(subset%l)
575 40 : IF (tmp_l(il) == 0) EXIT
576 48 : subset_new%l(il) = tmp_l(il)
577 : END DO
578 16 : DEALLOCATE (tmp_l)
579 16 : iind = 0
580 104 : DO icon = 1, subset%ncon_tot
581 104 : IF (in_use(icon)) THEN
582 44 : iind = iind + 1
583 352 : subset_new%coeff(:, iind) = subset%coeff(:, icon)
584 : END IF
585 : END DO
586 :
587 16 : END SUBROUTINE create_new_subset
588 :
589 : ! **************************************************************************************************
590 : !> \brief for completeness generate the derived info for set 0(reference from file)
591 : !> \param info ...
592 : !> \param basis ...
593 : !> \author Florian Schiffmann
594 : ! **************************************************************************************************
595 :
596 8 : SUBROUTINE init_deriv_info_ref(info, basis)
597 : TYPE(derived_basis_info) :: info
598 : TYPE(flex_basis_type) :: basis
599 :
600 : INTEGER :: i
601 :
602 24 : ALLOCATE (info%in_use_set(basis%nsets))
603 16 : info%in_use_set = .TRUE.
604 32 : ALLOCATE (info%use_contr(basis%nsets))
605 16 : DO i = 1, basis%nsets
606 24 : ALLOCATE (info%use_contr(i)%in_use(basis%subset(i)%ncon_tot))
607 60 : info%use_contr(i)%in_use = .TRUE.
608 : END DO
609 :
610 8 : END SUBROUTINE init_deriv_info_ref
611 :
612 : ! **************************************************************************************************
613 : !> \brief get the general information for the basis sets. E.g. what to optimize,
614 : !> Basis set name, constraints upon optimization and read the reference basis
615 : !> \param kind_section ...
616 : !> \param opt_bas ...
617 : !> \param para_env ...
618 : !> \author Florian Schiffmann
619 : ! **************************************************************************************************
620 :
621 4 : SUBROUTINE generate_initial_basis(kind_section, opt_bas, para_env)
622 : TYPE(section_vals_type), POINTER :: kind_section
623 : TYPE(basis_optimization_type) :: opt_bas
624 : TYPE(mp_para_env_type), POINTER :: para_env
625 :
626 : INTEGER :: ikind, variable_counter
627 : LOGICAL :: explicit
628 : TYPE(section_vals_type), POINTER :: set_section
629 :
630 4 : CALL section_vals_get(kind_section, n_repetition=opt_bas%nkind)
631 20 : ALLOCATE (opt_bas%kind_basis(opt_bas%nkind))
632 :
633 : ! counter to get the number of free variables in optimization
634 4 : variable_counter = 0
635 12 : DO ikind = 1, opt_bas%nkind
636 : CALL section_vals_val_get(kind_section, "_SECTION_PARAMETERS_", c_val=opt_bas%kind_basis(ikind)%element, &
637 8 : i_rep_section=ikind)
638 : CALL section_vals_val_get(kind_section, "BASIS_SET", c_val=opt_bas%kind_basis(ikind)%basis_name, &
639 8 : i_rep_section=ikind)
640 : set_section => section_vals_get_subs_vals(kind_section, "DERIVED_BASIS_SETS", &
641 8 : i_rep_section=ikind)
642 8 : CALL section_vals_get(set_section, n_repetition=opt_bas%kind_basis(ikind)%nbasis_deriv, explicit=explicit)
643 8 : IF (.NOT. explicit) opt_bas%kind_basis(ikind)%nbasis_deriv = 0
644 48 : ALLOCATE (opt_bas%kind_basis(ikind)%flex_basis(0:opt_bas%kind_basis(ikind)%nbasis_deriv))
645 48 : ALLOCATE (opt_bas%kind_basis(ikind)%deriv_info(0:opt_bas%kind_basis(ikind)%nbasis_deriv))
646 :
647 : CALL fill_basis_template(kind_section, opt_bas%kind_basis(ikind)%flex_basis(0), opt_bas%template_basis_file, &
648 8 : opt_bas%kind_basis(ikind)%element, opt_bas%kind_basis(ikind)%basis_name, para_env, ikind)
649 :
650 8 : CALL setup_exp_constraints(kind_section, opt_bas%kind_basis(ikind)%flex_basis(0))
651 :
652 8 : CALL parse_derived_basis(kind_section, opt_bas%kind_basis(ikind)%deriv_info, ikind)
653 :
654 20 : variable_counter = variable_counter + opt_bas%kind_basis(ikind)%flex_basis(0)%nopt
655 : END DO
656 :
657 12 : ALLOCATE (opt_bas%x_opt(variable_counter))
658 :
659 4 : variable_counter = 0
660 12 : DO ikind = 1, opt_bas%nkind
661 12 : CALL assign_x_to_basis(opt_bas%x_opt, opt_bas%kind_basis(ikind)%flex_basis(0), variable_counter)
662 : END DO
663 :
664 4 : CPASSERT(variable_counter == SIZE(opt_bas%x_opt))
665 :
666 4 : END SUBROUTINE generate_initial_basis
667 :
668 : ! **************************************************************************************************
669 : !> \brief get low level information about how to construc new basis sets from reference
670 : !> \param kind_section ...
671 : !> \param deriv_info ...
672 : !> \param ikind ...
673 : !> \author Florian Schiffmann
674 : ! **************************************************************************************************
675 :
676 8 : SUBROUTINE parse_derived_basis(kind_section, deriv_info, ikind)
677 : TYPE(section_vals_type), POINTER :: kind_section
678 : TYPE(derived_basis_info), DIMENSION(:) :: deriv_info
679 : INTEGER :: ikind
680 :
681 : INTEGER :: i_rep, iset, jset, n_rep, nsets
682 8 : INTEGER, DIMENSION(:), POINTER :: i_vals
683 : LOGICAL :: explicit
684 : TYPE(section_vals_type), POINTER :: set1_section
685 :
686 8 : nsets = SIZE(deriv_info) - 1
687 : set1_section => section_vals_get_subs_vals(kind_section, "DERIVED_BASIS_SETS", &
688 16 : i_rep_section=ikind)
689 24 : DO jset = 1, nsets
690 : ! stracnge but as derive info is allcated from 0 to n the count over here has to be shifted
691 16 : iset = jset + 1
692 : CALL section_vals_val_get(set1_section, "BASIS_SET_NAME", c_val=deriv_info(iset)%basis_name, &
693 16 : i_rep_section=jset)
694 16 : CALL section_vals_val_get(set1_section, "REFERENCE_SET", i_vals=i_vals, i_rep_section=jset)
695 16 : deriv_info(iset)%reference_set = i_vals(1)
696 : CALL section_vals_val_get(set1_section, "REMOVE_CONTRACTION", explicit=explicit, n_rep_val=n_rep, &
697 16 : i_rep_section=jset)
698 16 : deriv_info(iset)%ncontr = n_rep
699 16 : IF (explicit) THEN
700 48 : ALLOCATE (deriv_info(iset)%remove_contr(n_rep, 3))
701 48 : DO i_rep = 1, n_rep
702 : CALL section_vals_val_get(set1_section, "REMOVE_CONTRACTION", i_rep_val=i_rep, i_vals=i_vals, &
703 32 : i_rep_section=jset)
704 144 : deriv_info(iset)%remove_contr(i_rep, :) = i_vals(:)
705 : END DO
706 : END IF
707 : CALL section_vals_val_get(set1_section, "REMOVE_SET", explicit=explicit, n_rep_val=n_rep, &
708 16 : i_rep_section=jset)
709 16 : deriv_info(iset)%nsets = n_rep
710 40 : IF (explicit) THEN
711 0 : ALLOCATE (deriv_info(iset)%remove_set(n_rep))
712 0 : DO i_rep = 1, n_rep
713 : CALL section_vals_val_get(set1_section, "REMOVE_SET", i_rep_val=i_rep, i_vals=i_vals, &
714 0 : i_rep_section=jset)
715 0 : deriv_info(iset)%remove_set(i_rep) = i_vals(1)
716 : END DO
717 : END IF
718 : END DO
719 :
720 8 : END SUBROUTINE parse_derived_basis
721 :
722 : ! **************************************************************************************************
723 : !> \brief get low level information about constraint on exponents
724 : !> \param kind1_section ...
725 : !> \param flex_basis ...
726 : !> \author Florian Schiffmann
727 : ! **************************************************************************************************
728 :
729 16 : SUBROUTINE setup_exp_constraints(kind1_section, flex_basis)
730 : TYPE(section_vals_type), POINTER :: kind1_section
731 : TYPE(flex_basis_type) :: flex_basis
732 :
733 : INTEGER :: ipgf, irep, iset, nrep
734 8 : INTEGER, DIMENSION(:), POINTER :: def_exp
735 : LOGICAL :: is_bound, is_varlim
736 : TYPE(section_vals_type), POINTER :: const_section
737 :
738 16 : const_section => section_vals_get_subs_vals(kind1_section, "CONSTRAIN_EXPONENTS")
739 8 : CALL section_vals_get(const_section, n_repetition=nrep)
740 8 : DO irep = 1, nrep
741 0 : CALL section_vals_val_get(const_section, "USE_EXP", i_vals=def_exp, i_rep_section=irep)
742 0 : CALL section_vals_val_get(const_section, "BOUNDARIES", explicit=is_bound, i_rep_section=irep)
743 0 : CALL section_vals_val_get(const_section, "MAX_VAR_FRACTION", explicit=is_varlim, i_rep_section=irep)
744 0 : IF (is_bound .AND. is_varlim) &
745 : CALL cp_abort(__LOCATION__, "Exponent has two constraints. "// &
746 0 : "This is not possible at the moment. Please change input.")
747 0 : IF (.NOT. is_bound .AND. .NOT. is_varlim) &
748 : CALL cp_abort(__LOCATION__, "Exponent is declared to be constraint but none is given"// &
749 0 : " Please change input.")
750 8 : IF (def_exp(1) == -1) THEN
751 0 : DO iset = 1, flex_basis%nsets
752 0 : IF (def_exp(2) == -1) THEN
753 0 : DO ipgf = 1, flex_basis%subset(iset)%nexp
754 0 : CALL set_constraint(flex_basis, iset, ipgf, const_section, is_bound, is_varlim, irep)
755 : END DO
756 : ELSE
757 0 : IF (def_exp(2) .LE. flex_basis%subset(iset)%nexp) &
758 : CALL cp_abort(__LOCATION__, &
759 : "Exponent declared in constraint is larger than number of exponents in the set"// &
760 0 : " Please change input.")
761 0 : CALL set_constraint(flex_basis, iset, def_exp(2), const_section, is_bound, is_varlim, irep)
762 : END IF
763 : END DO
764 : ELSE
765 0 : IF (.NOT. def_exp(1) .LE. flex_basis%nsets) &
766 : CALL cp_abort(__LOCATION__, &
767 : "Set number of constraint is larger than number of sets in the template basis set."// &
768 0 : " Please change input.")
769 0 : IF (def_exp(2) == -1) THEN
770 0 : DO ipgf = 1, flex_basis%subset(iset)%nexp
771 0 : CALL set_constraint(flex_basis, def_exp(1), ipgf, const_section, is_bound, is_varlim, irep)
772 : END DO
773 : ELSE
774 0 : IF (.NOT. def_exp(2) .LE. flex_basis%subset(def_exp(1))%nexp) &
775 : CALL cp_abort(__LOCATION__, &
776 : "Exponent declared in constraint is larger than number of exponents in the set"// &
777 0 : " Please change input.")
778 0 : CALL set_constraint(flex_basis, def_exp(1), def_exp(2), const_section, is_bound, is_varlim, irep)
779 : END IF
780 : END IF
781 : END DO
782 :
783 8 : END SUBROUTINE setup_exp_constraints
784 :
785 : ! **************************************************************************************************
786 : !> \brief put the constraint information in type and process if requires
787 : !> BOUNDARIES constraint gets transformed into MAX_VAR_FRACTION constraint.
788 : !> \param flex_basis ...
789 : !> \param iset ...
790 : !> \param ipgf ...
791 : !> \param const_section ...
792 : !> \param is_bound ...
793 : !> \param is_varlim ...
794 : !> \param irep ...
795 : !> \author Florian Schiffmann
796 : ! **************************************************************************************************
797 :
798 0 : SUBROUTINE set_constraint(flex_basis, iset, ipgf, const_section, is_bound, is_varlim, irep)
799 : TYPE(flex_basis_type) :: flex_basis
800 : INTEGER :: iset, ipgf
801 : TYPE(section_vals_type), POINTER :: const_section
802 : LOGICAL :: is_bound, is_varlim
803 : INTEGER :: irep
804 :
805 : REAL(KIND=dp) :: r_val
806 0 : REAL(KIND=dp), DIMENSION(:), POINTER :: r_vals
807 :
808 0 : IF (flex_basis%subset(iset)%exp_has_const(ipgf)) &
809 : CALL cp_abort(__LOCATION__, &
810 : "Multiple constraints due to collision in CONSTRAIN_EXPONENTS."// &
811 0 : " Please change input.")
812 0 : flex_basis%subset(iset)%exp_has_const(ipgf) = .TRUE.
813 0 : IF (is_bound) THEN
814 0 : flex_basis%subset(iset)%exp_const(ipgf)%const_type = 0
815 0 : CALL section_vals_val_get(const_section, "BOUNDARIES", r_vals=r_vals, i_rep_section=irep)
816 0 : flex_basis%subset(iset)%exp_const(ipgf)%llim = MINVAL(r_vals)
817 0 : flex_basis%subset(iset)%exp_const(ipgf)%ulim = MAXVAL(r_vals)
818 0 : r_val = flex_basis%subset(iset)%exps(ipgf)
819 0 : IF (flex_basis%subset(iset)%exps(ipgf) .GT. MAXVAL(r_vals) .OR. flex_basis%subset(iset)%exps(ipgf) .LT. MINVAL(r_vals)) &
820 : CALL cp_abort(__LOCATION__, &
821 : "Exponent "//cp_to_string(r_val)// &
822 : " declared in constraint is out of bounds of constraint"//cp_to_string(MINVAL(r_vals))// &
823 : " to"//cp_to_string(MAXVAL(r_vals))// &
824 0 : " Please change input.")
825 0 : flex_basis%subset(iset)%exp_const(ipgf)%init = SUM(r_vals)/2.0_dp
826 0 : flex_basis%subset(iset)%exp_const(ipgf)%var_fac = MAXVAL(r_vals)/flex_basis%subset(iset)%exp_const(ipgf)%init - 1.0_dp
827 : END IF
828 0 : IF (is_varlim) THEN
829 0 : flex_basis%subset(iset)%exp_const(ipgf)%const_type = 1
830 0 : CALL section_vals_val_get(const_section, "MAX_VAR_FRACTION", r_vals=r_vals, i_rep_section=irep)
831 0 : flex_basis%subset(iset)%exp_const(ipgf)%var_fac = r_vals(1)
832 0 : flex_basis%subset(iset)%exp_const(ipgf)%init = flex_basis%subset(iset)%exps(ipgf)
833 : END IF
834 :
835 0 : END SUBROUTINE set_constraint
836 :
837 : ! **************************************************************************************************
838 : !> \brief Initialize the optimization vector with the values from the refernece sets
839 : !> \param x ...
840 : !> \param basis ...
841 : !> \param x_ind ...
842 : !> \author Florian Schiffmann
843 : ! **************************************************************************************************
844 :
845 8 : SUBROUTINE assign_x_to_basis(x, basis, x_ind)
846 : REAL(KIND=dp), DIMENSION(:) :: x
847 : TYPE(flex_basis_type) :: basis
848 : INTEGER :: x_ind
849 :
850 : INTEGER :: icont, ipgf, iset
851 :
852 16 : DO iset = 1, basis%nsets
853 72 : DO ipgf = 1, basis%subset(iset)%nexp
854 56 : IF (basis%subset(iset)%opt_exps(ipgf)) THEN
855 0 : x_ind = x_ind + 1
856 0 : basis%subset(iset)%exp_x_ind(ipgf) = x_ind
857 0 : x(x_ind) = basis%subset(iset)%exps(ipgf)
858 : END IF
859 372 : DO icont = 1, basis%subset(iset)%ncon_tot
860 364 : IF (basis%subset(iset)%opt_coeff(ipgf, icont)) THEN
861 308 : x_ind = x_ind + 1
862 308 : basis%subset(iset)%coeff_x_ind(ipgf, icont) = x_ind
863 308 : x(x_ind) = basis%subset(iset)%coeff(ipgf, icont)
864 : END IF
865 : END DO
866 : END DO
867 : END DO
868 :
869 8 : END SUBROUTINE assign_x_to_basis
870 :
871 : ! **************************************************************************************************
872 : !> \brief Fill the reference set and get the free varialbles from input
873 : !> \param kind1_section ...
874 : !> \param flex_basis ...
875 : !> \param template_basis_file ...
876 : !> \param element ...
877 : !> \param basis_name ...
878 : !> \param para_env ...
879 : !> \param ikind ...
880 : !> \author Florian Schiffmann
881 : ! **************************************************************************************************
882 :
883 48 : SUBROUTINE fill_basis_template(kind1_section, flex_basis, template_basis_file, element, basis_name, para_env, ikind)
884 : TYPE(section_vals_type), POINTER :: kind1_section
885 : TYPE(flex_basis_type) :: flex_basis
886 : CHARACTER(LEN=default_path_length) :: template_basis_file
887 : CHARACTER(LEN=default_string_length) :: element, basis_name
888 : TYPE(mp_para_env_type), POINTER :: para_env
889 : INTEGER :: ikind
890 :
891 : INTEGER :: icont, idof, ipgf, irep, iset, nrep
892 8 : INTEGER, DIMENSION(:), POINTER :: switch
893 :
894 8 : CALL parse_basis(flex_basis, template_basis_file, element, basis_name, para_env)
895 :
896 : ! get the optimizable parameters. Many way to modify them but in the end only logical matrix
897 : ! is either set or values get flipped according to the input
898 : CALL section_vals_val_get(kind1_section, "INITIAL_DEGREES_OF_FREEDOM", i_val=idof, &
899 8 : i_rep_section=ikind)
900 16 : DO iset = 1, flex_basis%nsets
901 8 : SELECT CASE (idof)
902 : CASE (do_opt_none)
903 : ! initialization in parse subset did the job
904 : CASE (do_opt_all)
905 0 : flex_basis%subset(iset)%opt_coeff = .TRUE.
906 0 : flex_basis%subset(iset)%opt_exps = .TRUE.
907 : CASE (do_opt_coeff)
908 360 : flex_basis%subset(iset)%opt_coeff = .TRUE.
909 : CASE (do_opt_exps)
910 0 : flex_basis%subset(iset)%opt_exps = .TRUE.
911 : CASE DEFAULT
912 8 : CPABORT("No initialization available?????")
913 : END SELECT
914 : END DO
915 :
916 8 : CALL section_vals_val_get(kind1_section, "SWITCH_CONTRACTION_STATE", n_rep_val=nrep, i_rep_section=ikind)
917 8 : DO irep = 1, nrep
918 : CALL section_vals_val_get(kind1_section, "SWITCH_CONTRACTION_STATE", i_rep_val=irep, &
919 0 : i_rep_section=ikind, i_vals=switch)
920 0 : icont = convert_l_contr_to_entry(flex_basis%subset(switch(1))%lmin, flex_basis%subset(switch(1))%l, switch(3), switch(2))
921 8 : DO ipgf = 1, flex_basis%subset(switch(1))%nexp
922 0 : flex_basis%subset(switch(1))%opt_coeff(ipgf, icont) = .NOT. flex_basis%subset(switch(1))%opt_coeff(ipgf, icont)
923 : END DO
924 : END DO
925 :
926 8 : CALL section_vals_val_get(kind1_section, "SWITCH_COEFF_STATE", n_rep_val=nrep, i_rep_section=ikind)
927 8 : DO irep = 1, nrep
928 : CALL section_vals_val_get(kind1_section, "SWITCH_COEFF_STATE", i_rep_val=irep, &
929 0 : i_rep_section=ikind, i_vals=switch)
930 0 : icont = convert_l_contr_to_entry(flex_basis%subset(switch(1))%lmin, flex_basis%subset(switch(1))%l, switch(3), switch(2))
931 : flex_basis%subset(switch(1))%opt_coeff(switch(4), icont) = &
932 8 : .NOT. flex_basis%subset(switch(1))%opt_coeff(switch(4), icont)
933 : END DO
934 :
935 8 : CALL section_vals_val_get(kind1_section, "SWITCH_EXP_STATE", n_rep_val=nrep, i_rep_section=ikind)
936 8 : DO irep = 1, nrep
937 : CALL section_vals_val_get(kind1_section, "SWITCH_EXP_STATE", i_rep_val=irep, &
938 0 : i_rep_section=ikind, i_vals=switch)
939 8 : flex_basis%subset(switch(1))%opt_exps(switch(2)) = .NOT. flex_basis%subset(switch(1))%opt_exps(switch(2))
940 : END DO
941 :
942 8 : CALL section_vals_val_get(kind1_section, "SWITCH_SET_STATE", n_rep_val=nrep, i_rep_section=ikind)
943 8 : DO irep = 1, nrep
944 : CALL section_vals_val_get(kind1_section, "SWITCH_SET_STATE", i_rep_val=irep, &
945 0 : i_rep_section=ikind, i_vals=switch)
946 8 : DO ipgf = 1, flex_basis%subset(switch(2))%nexp
947 0 : SELECT CASE (switch(1))
948 : CASE (0) ! switch all states in the set
949 0 : DO icont = 1, flex_basis%subset(switch(2))%ncon_tot
950 : flex_basis%subset(switch(2))%opt_coeff(ipgf, icont) = &
951 0 : .NOT. flex_basis%subset(switch(2))%opt_coeff(ipgf, icont)
952 : END DO
953 0 : flex_basis%subset(switch(2))%opt_exps(ipgf) = .NOT. flex_basis%subset(switch(2))%opt_exps(ipgf)
954 : CASE (1) ! switch only exp
955 0 : flex_basis%subset(switch(2))%opt_exps(ipgf) = .NOT. flex_basis%subset(switch(2))%opt_exps(ipgf)
956 : CASE (2) ! switch only coeff
957 0 : DO icont = 1, flex_basis%subset(switch(2))%ncon_tot
958 : flex_basis%subset(switch(2))%opt_coeff(ipgf, icont) = &
959 0 : .NOT. flex_basis%subset(switch(2))%opt_coeff(ipgf, icont)
960 : END DO
961 : CASE DEFAULT
962 0 : CPABORT("Invalid option in SWITCH_SET_STATE, 1st value has to be 0, 1 or 2")
963 : END SELECT
964 : END DO
965 : END DO
966 :
967 : ! perform a final modification. If basis set is uncontracted coefficient will never have to be optimized
968 16 : DO irep = 1, flex_basis%nsets
969 16 : IF (flex_basis%subset(irep)%nexp == 1) THEN
970 0 : DO ipgf = 1, flex_basis%subset(irep)%nexp
971 0 : flex_basis%subset(irep)%opt_coeff(ipgf, 1) = .FALSE.
972 : END DO
973 : END IF
974 : END DO
975 :
976 : ! finally count the total number of free parameters
977 8 : flex_basis%nopt = 0
978 16 : DO irep = 1, flex_basis%nsets
979 72 : DO ipgf = 1, flex_basis%subset(irep)%nexp
980 364 : DO icont = 1, flex_basis%subset(irep)%ncon_tot
981 364 : IF (flex_basis%subset(irep)%opt_coeff(ipgf, icont)) flex_basis%nopt = flex_basis%nopt + 1
982 : END DO
983 64 : IF (flex_basis%subset(irep)%opt_exps(ipgf)) flex_basis%nopt = flex_basis%nopt + 1
984 : END DO
985 : END DO
986 :
987 8 : END SUBROUTINE fill_basis_template
988 :
989 : ! **************************************************************************************************
990 : !> \brief Helper function to parse input. Converts l and index position of
991 : !> a contraction to index in the contraction array of the set using lmin and nl
992 : !> \param lmin ...
993 : !> \param nl ...
994 : !> \param icontr ...
995 : !> \param l ...
996 : !> \return ...
997 : !> \author Florian Schiffmann
998 : ! **************************************************************************************************
999 :
1000 120 : FUNCTION convert_l_contr_to_entry(lmin, nl, icontr, l) RESULT(ientry)
1001 : INTEGER :: lmin
1002 : INTEGER, DIMENSION(:) :: nl
1003 : INTEGER :: icontr, l, ientry
1004 :
1005 : INTEGER :: i, icon2l, iwork
1006 :
1007 120 : iwork = l - lmin
1008 120 : icon2l = 0
1009 188 : DO i = 1, iwork
1010 188 : icon2l = icon2l + nl(i)
1011 : END DO
1012 120 : ientry = icon2l + icontr
1013 :
1014 120 : END FUNCTION convert_l_contr_to_entry
1015 :
1016 : ! **************************************************************************************************
1017 : !> \brief Read the reference basis sets from the template basis file
1018 : !> \param flex_basis ...
1019 : !> \param template_basis_file ...
1020 : !> \param element ...
1021 : !> \param basis_name ...
1022 : !> \param para_env ...
1023 : !> \author Florian Schiffmann
1024 : ! **************************************************************************************************
1025 :
1026 16 : SUBROUTINE parse_basis(flex_basis, template_basis_file, element, basis_name, para_env)
1027 : TYPE(flex_basis_type) :: flex_basis
1028 : CHARACTER(LEN=default_path_length) :: template_basis_file
1029 : CHARACTER(LEN=default_string_length) :: element, basis_name
1030 : TYPE(mp_para_env_type), POINTER :: para_env
1031 :
1032 : CHARACTER(LEN=240) :: line
1033 : CHARACTER(LEN=242) :: line2
1034 : CHARACTER(LEN=LEN(basis_name)+2) :: basis_name2
1035 : CHARACTER(LEN=LEN(element)+2) :: element2
1036 : INTEGER :: iset, strlen1, strlen2
1037 : LOGICAL :: basis_found, found, match
1038 : TYPE(cp_parser_type) :: parser
1039 :
1040 8 : basis_found = .FALSE.
1041 8 : CALL uppercase(element)
1042 8 : CALL uppercase(basis_name)
1043 8 : CALL parser_create(parser, template_basis_file, para_env=para_env)
1044 :
1045 : search_loop: DO
1046 20 : CALL parser_search_string(parser, TRIM(basis_name), .TRUE., found, line)
1047 20 : IF (found) THEN
1048 20 : match = .FALSE.
1049 20 : CALL uppercase(line)
1050 : ! Check both the element symbol and the basis set name
1051 20 : line2 = " "//line//" "
1052 20 : element2 = " "//TRIM(element)//" "
1053 20 : basis_name2 = " "//TRIM(basis_name)//" "
1054 20 : strlen1 = LEN_TRIM(element2) + 1
1055 20 : strlen2 = LEN_TRIM(basis_name2) + 1
1056 20 : IF ((INDEX(line2, element2(:strlen1)) > 0) .AND. &
1057 8 : (INDEX(line2, basis_name2(:strlen2)) > 0)) match = .TRUE.
1058 20 : IF (match) THEN
1059 8 : CALL parser_get_object(parser, flex_basis%nsets, newline=.TRUE.)
1060 32 : ALLOCATE (flex_basis%subset(flex_basis%nsets))
1061 16 : DO iset = 1, flex_basis%nsets
1062 16 : CALL parse_subset(parser, flex_basis%subset(iset))
1063 : END DO
1064 : basis_found = .TRUE.
1065 : EXIT
1066 : END IF
1067 : ELSE
1068 : EXIT search_loop
1069 : END IF
1070 : END DO search_loop
1071 8 : CALL parser_release(parser)
1072 :
1073 8 : IF (.NOT. basis_found) CALL cp_abort(__LOCATION__, &
1074 : "The requested basis set <"//TRIM(basis_name)// &
1075 : "> for element <"//TRIM(element)//"> was not "// &
1076 0 : "found in the template basis set file ")
1077 :
1078 24 : END SUBROUTINE parse_basis
1079 :
1080 : ! **************************************************************************************************
1081 : !> \brief Read the subset information from the template basis file
1082 : !> \param parser ...
1083 : !> \param subset ...
1084 : !> \author Florian Schiffmann
1085 : ! **************************************************************************************************
1086 8 : SUBROUTINE parse_subset(parser, subset)
1087 : TYPE(cp_parser_type), INTENT(INOUT) :: parser
1088 : TYPE(subset_type) :: subset
1089 :
1090 : CHARACTER(len=20*default_string_length) :: line_att
1091 : INTEGER :: icon1, icon2, il, ipgf, ishell, istart
1092 : REAL(KIND=dp) :: gs_scale
1093 : REAL(KIND=dp), POINTER :: r_val
1094 :
1095 8 : line_att = ""
1096 8 : CALL parser_get_object(parser, subset%n, newline=.TRUE.)
1097 8 : CALL parser_get_object(parser, subset%lmin)
1098 8 : CALL parser_get_object(parser, subset%lmax)
1099 8 : CALL parser_get_object(parser, subset%nexp)
1100 8 : subset%nl = subset%lmax - subset%lmin + 1
1101 8 : ALLOCATE (r_val)
1102 24 : ALLOCATE (subset%l(subset%nl))
1103 24 : ALLOCATE (subset%exps(subset%nexp))
1104 24 : ALLOCATE (subset%exp_has_const(subset%nexp))
1105 64 : subset%exp_has_const = .FALSE.
1106 16 : ALLOCATE (subset%opt_exps(subset%nexp))
1107 64 : subset%opt_exps = .FALSE.
1108 80 : ALLOCATE (subset%exp_const(subset%nexp))
1109 16 : ALLOCATE (subset%exp_x_ind(subset%nexp))
1110 28 : DO ishell = 1, subset%nl
1111 28 : CALL parser_get_object(parser, subset%l(ishell))
1112 : END DO
1113 28 : subset%ncon_tot = SUM(subset%l)
1114 32 : ALLOCATE (subset%coeff(subset%nexp, subset%ncon_tot))
1115 32 : ALLOCATE (subset%opt_coeff(subset%nexp, subset%ncon_tot))
1116 360 : subset%opt_coeff = .FALSE.
1117 24 : ALLOCATE (subset%coeff_x_ind(subset%nexp, subset%ncon_tot))
1118 64 : DO ipgf = 1, subset%nexp
1119 56 : CALL parser_get_object(parser, r_val, newline=.TRUE.)
1120 56 : subset%exps(ipgf) = r_val
1121 372 : DO ishell = 1, subset%ncon_tot
1122 308 : CALL parser_get_object(parser, r_val)
1123 364 : subset%coeff(ipgf, ishell) = r_val
1124 : END DO
1125 : END DO
1126 :
1127 : ! orthonormalize contraction coefficients using gram schmidt
1128 8 : istart = 1
1129 28 : DO il = 1, subset%nl
1130 44 : DO icon1 = istart, istart + subset%l(il) - 2
1131 80 : DO icon2 = icon1 + 1, istart + subset%l(il) - 1
1132 : gs_scale = DOT_PRODUCT(subset%coeff(:, icon2), subset%coeff(:, icon1))/ &
1133 540 : DOT_PRODUCT(subset%coeff(:, icon1), subset%coeff(:, icon1))
1134 312 : subset%coeff(:, icon2) = subset%coeff(:, icon2) - gs_scale*subset%coeff(:, icon1)
1135 : END DO
1136 : END DO
1137 28 : istart = istart + subset%l(il)
1138 : END DO
1139 :
1140 : ! just to get an understandable basis normalize coefficients
1141 52 : DO icon1 = 1, subset%ncon_tot
1142 : subset%coeff(:, icon1) = subset%coeff(:, icon1)/ &
1143 668 : SQRT(DOT_PRODUCT(subset%coeff(:, icon1), subset%coeff(:, icon1)))
1144 : END DO
1145 8 : DEALLOCATE (r_val)
1146 :
1147 8 : END SUBROUTINE parse_subset
1148 :
1149 : ! **************************************************************************************************
1150 : !> \brief Initialize the variables for the powell optimizer
1151 : !> \param p_param ...
1152 : !> \param powell_section ...
1153 : !> \author Florian Schiffmann
1154 : ! **************************************************************************************************
1155 :
1156 4 : SUBROUTINE init_powell_var(p_param, powell_section)
1157 : TYPE(opt_state_type), INTENT(INOUT) :: p_param
1158 : TYPE(section_vals_type), POINTER :: powell_section
1159 :
1160 4 : p_param%state = 0
1161 4 : p_param%nvar = 0
1162 4 : p_param%iprint = 0
1163 4 : p_param%unit = default_output_unit
1164 4 : CALL section_vals_val_get(powell_section, "ACCURACY", r_val=p_param%rhoend)
1165 4 : CALL section_vals_val_get(powell_section, "STEP_SIZE", r_val=p_param%rhobeg)
1166 4 : CALL section_vals_val_get(powell_section, "MAX_FUN", i_val=p_param%maxfun)
1167 :
1168 4 : END SUBROUTINE init_powell_var
1169 :
1170 : END MODULE optimize_basis_utils
|