LCOV - code coverage report
Current view: top level - src - optimize_basis.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:24d69ee) Lines: 94.5 % 542 512
Test Date: 2026-09-03 07:32:15 Functions: 100.0 % 16 16

            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
        

Generated by: LCOV version 2.0-1