LCOV - code coverage report
Current view: top level - src/motion - bfgs_optimizer.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:21ef868) Lines: 93.8 % 561 526
Test Date: 2026-08-14 07:04:57 Functions: 100.0 % 12 12

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2026 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \brief Routines for Geometry optimization using BFGS algorithm
      10              : !> \par History
      11              : !>      Module modified by Pierre-André Cazade [pcazade] 01.2020 - University of Limerick.
      12              : !>      Modifications enable Space Group Symmetry.
      13              : ! **************************************************************************************************
      14              : MODULE bfgs_optimizer
      15              : 
      16              :    USE atomic_kind_list_types, ONLY: atomic_kind_list_type
      17              :    USE atomic_kind_types, ONLY: get_atomic_kind, &
      18              :                                 get_atomic_kind_set
      19              :    USE cell_types, ONLY: cell_type, &
      20              :                          pbc
      21              :    USE constraint_fxd, ONLY: fix_atom_control
      22              :    USE cp_blacs_env, ONLY: cp_blacs_env_create, &
      23              :                            cp_blacs_env_release, &
      24              :                            cp_blacs_env_type
      25              :    USE cp_external_control, ONLY: external_control
      26              :    USE cp_files, ONLY: close_file, &
      27              :                        open_file
      28              :    USE cp_fm_basic_linalg, ONLY: cp_fm_column_scale, &
      29              :                                  cp_fm_transpose
      30              :    USE cp_fm_diag, ONLY: choose_eigv_solver
      31              :    USE cp_fm_struct, ONLY: cp_fm_struct_create, &
      32              :                            cp_fm_struct_release, &
      33              :                            cp_fm_struct_type
      34              :    USE cp_fm_types, ONLY: &
      35              :       cp_fm_get_info, &
      36              :       cp_fm_read_unformatted, &
      37              :       cp_fm_set_all, &
      38              :       cp_fm_to_fm, &
      39              :       cp_fm_type, &
      40              :       cp_fm_write_unformatted, cp_fm_create, cp_fm_release
      41              :    USE parallel_gemm_api, ONLY: parallel_gemm
      42              :    USE cp_log_handling, ONLY: cp_get_default_logger, &
      43              :                               cp_logger_type, &
      44              :                               cp_to_string
      45              :    USE cp_output_handling, ONLY: cp_iterate, &
      46              :                                  cp_p_file, &
      47              :                                  cp_print_key_finished_output, &
      48              :                                  cp_print_key_should_output, &
      49              :                                  cp_print_key_unit_nr
      50              :    USE message_passing, ONLY: mp_para_env_type
      51              :    USE cp_subsys_types, ONLY: cp_subsys_get, &
      52              :                               cp_subsys_type
      53              :    USE force_env_types, ONLY: force_env_get, &
      54              :                               force_env_type
      55              :    USE global_types, ONLY: global_environment_type
      56              :    USE gopt_f_methods, ONLY: gopt_f_ii, &
      57              :                              gopt_f_io, &
      58              :                              gopt_f_io_finalize, &
      59              :                              gopt_f_io_init, &
      60              :                              print_geo_opt_header, &
      61              :                              print_geo_opt_nc
      62              :    USE gopt_f_types, ONLY: gopt_f_type
      63              :    USE gopt_param_types, ONLY: gopt_param_type
      64              :    USE input_constants, ONLY: default_cell_method_id, &
      65              :                               default_ts_method_id
      66              :    USE input_section_types, ONLY: section_vals_get_subs_vals, &
      67              :                                   section_vals_type, &
      68              :                                   section_vals_val_get, &
      69              :                                   section_vals_val_set
      70              :    USE kinds, ONLY: default_path_length, &
      71              :                     dp
      72              :    USE machine, ONLY: m_flush, &
      73              :                       m_walltime
      74              :    USE particle_list_types, ONLY: particle_list_type
      75              :    USE space_groups, ONLY: identify_space_group, &
      76              :                            print_spgr, &
      77              :                            spgr_apply_rotations_coord, &
      78              :                            spgr_apply_rotations_force
      79              :    USE space_groups_types, ONLY: spgr_type
      80              :    USE bibliography, ONLY: Lindh1995, &
      81              :                            cite_reference
      82              : 
      83              : #include "../base/base_uses.f90"
      84              : 
      85              :    IMPLICIT NONE
      86              :    PRIVATE
      87              : 
      88              :    #:include "gopt_f77_methods.fypp"
      89              : 
      90              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'bfgs_optimizer'
      91              :    LOGICAL, PARAMETER                   :: debug_this_module = .TRUE.
      92              : 
      93              :    PUBLIC :: geoopt_bfgs
      94              : 
      95              : CONTAINS
      96              : 
      97              : ! **************************************************************************************************
      98              : !> \brief Main driver for BFGS geometry optimizations
      99              : !> \param force_env ...
     100              : !> \param gopt_param ...
     101              : !> \param globenv ...
     102              : !> \param geo_section ...
     103              : !> \param gopt_env ...
     104              : !> \param x0 ...
     105              : !> \par History
     106              : !>      01.2020 modified to perform Space Group Symmetry [pcazade]
     107              : ! **************************************************************************************************
     108          879 :    RECURSIVE SUBROUTINE geoopt_bfgs(force_env, gopt_param, globenv, geo_section, gopt_env, x0)
     109              : 
     110              :       TYPE(force_env_type), POINTER                      :: force_env
     111              :       TYPE(gopt_param_type), POINTER                     :: gopt_param
     112              :       TYPE(global_environment_type), POINTER             :: globenv
     113              :       TYPE(section_vals_type), POINTER                   :: geo_section
     114              :       TYPE(gopt_f_type), POINTER                         :: gopt_env
     115              :       REAL(KIND=dp), DIMENSION(:), POINTER               :: x0
     116              : 
     117              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'geoopt_bfgs'
     118              :       REAL(KIND=dp), PARAMETER                           :: one = 1.0_dp, zero = 0.0_dp
     119              : 
     120              :       CHARACTER(LEN=5)                                   :: wildcard
     121              :       CHARACTER(LEN=default_path_length)                 :: hes_filename
     122              :       INTEGER                                            :: handle, hesunit_read, indf, info, &
     123              :                                                             iter_nr, its, maxiter, ndf, nfree, &
     124              :                                                             output_unit
     125              :       LOGICAL                                            :: conv, hesrest, ionode, shell_present, &
     126              :                                                             should_stop, use_mod_hes, use_rfo
     127              :       REAL(KIND=dp)                                      :: ediff, emin, eold, etot, pred, rad, rat, &
     128              :                                                             step, t_diff, t_now, t_old
     129          879 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: dg, dr, dx, eigval, gold, work, xold
     130          879 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: g
     131              :       TYPE(atomic_kind_list_type), POINTER               :: atomic_kinds
     132              :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env
     133              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct_hes
     134              :       TYPE(cp_fm_type)                          :: eigvec_mat, hess_mat, hess_tmp
     135              :       TYPE(cp_logger_type), POINTER                      :: logger
     136              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     137              :       TYPE(cp_subsys_type), POINTER                      :: subsys
     138              :       TYPE(section_vals_type), POINTER                   :: print_key, root_section
     139              :       TYPE(spgr_type), POINTER                           :: spgr
     140              : 
     141          879 :       NULLIFY (logger, g, blacs_env, spgr)
     142         1758 :       logger => cp_get_default_logger()
     143          879 :       para_env => force_env%para_env
     144          879 :       root_section => force_env%root_section
     145          879 :       spgr => gopt_env%spgr
     146          879 :       t_old = m_walltime()
     147              : 
     148          879 :       CALL timeset(routineN, handle)
     149          879 :       CALL section_vals_val_get(geo_section, "BFGS%TRUST_RADIUS", r_val=rad)
     150          879 :       print_key => section_vals_get_subs_vals(geo_section, "BFGS%RESTART")
     151          879 :       ionode = para_env%is_source()
     152          879 :       maxiter = gopt_param%max_iter
     153          879 :       conv = .FALSE.
     154          879 :       rat = 0.0_dp
     155          879 :       wildcard = " BFGS"
     156          879 :       hes_filename = ""
     157              : 
     158              :       ! Stop if not yet implemented
     159          879 :       SELECT CASE (gopt_env%type_id)
     160              :       CASE (default_ts_method_id)
     161          879 :          CPABORT("BFGS method not yet working with DIMER")
     162              :       END SELECT
     163              : 
     164          879 :       CALL section_vals_val_get(geo_section, "BFGS%USE_RAT_FUN_OPT", l_val=use_rfo)
     165          879 :       CALL section_vals_val_get(geo_section, "BFGS%USE_MODEL_HESSIAN", l_val=use_mod_hes)
     166          879 :       CALL section_vals_val_get(geo_section, "BFGS%RESTART_HESSIAN", l_val=hesrest)
     167              :       output_unit = cp_print_key_unit_nr(logger, geo_section, "PRINT%PROGRAM_RUN_INFO", &
     168          879 :                                          extension=".geoLog")
     169          879 :       IF (output_unit > 0) THEN
     170          456 :          IF (use_rfo) THEN
     171              :             WRITE (UNIT=output_unit, FMT="(/,T2,A,T78,A3)") &
     172            5 :                "BFGS| Use rational function optimization for step estimation: ", "YES"
     173              :          ELSE
     174              :             WRITE (UNIT=output_unit, FMT="(/,T2,A,T78,A3)") &
     175          451 :                "BFGS| Use rational function optimization for step estimation: ", " NO"
     176              :          END IF
     177          456 :          IF (use_mod_hes) THEN
     178              :             WRITE (UNIT=output_unit, FMT="(T2,A,T78,A3)") &
     179          395 :                "BFGS| Use model Hessian for initial guess: ", "YES"
     180              :          ELSE
     181              :             WRITE (UNIT=output_unit, FMT="(T2,A,T78,A3)") &
     182           61 :                "BFGS| Use model Hessian for initial guess: ", " NO"
     183              :          END IF
     184          456 :          IF (hesrest) THEN
     185              :             WRITE (UNIT=output_unit, FMT="(T2,A,T78,A3)") &
     186            1 :                "BFGS| Restart Hessian: ", "YES"
     187              :          ELSE
     188              :             WRITE (UNIT=output_unit, FMT="(T2,A,T78,A3)") &
     189          455 :                "BFGS| Restart Hessian: ", " NO"
     190              :          END IF
     191              :          WRITE (UNIT=output_unit, FMT="(T2,A,T61,F20.3)") &
     192          456 :             "BFGS| Trust radius: ", rad
     193              :       END IF
     194              : 
     195          879 :       ndf = SIZE(x0)
     196          879 :       nfree = gopt_env%nfree
     197          879 :       IF (ndf > 3000) THEN
     198              :          CALL cp_warn(__LOCATION__, &
     199              :                       "The dimension of the Hessian matrix ("// &
     200              :                       TRIM(ADJUSTL(cp_to_string(ndf)))//") is greater than 3000. "// &
     201              :                       "The diagonalisation of the full Hessian  matrix needed for BFGS "// &
     202              :                       "is computationally expensive. You should consider to use the linear "// &
     203            0 :                       "scaling variant L-BFGS instead.")
     204              :       END IF
     205              : 
     206              :       ! Initialize hessian (hes = unitary matrix or model hessian )
     207              :       CALL cp_blacs_env_create(blacs_env, para_env, globenv%blacs_grid_layout, &
     208          879 :                                globenv%blacs_repeatable)
     209              :       CALL cp_fm_struct_create(fm_struct_hes, para_env=para_env, context=blacs_env, &
     210          879 :                                nrow_global=ndf, ncol_global=ndf)
     211          879 :       CALL cp_fm_create(hess_mat, fm_struct_hes, name="hess_mat")
     212          879 :       CALL cp_fm_create(hess_tmp, fm_struct_hes, name="hess_tmp")
     213          879 :       CALL cp_fm_create(eigvec_mat, fm_struct_hes, name="eigvec_mat")
     214         2637 :       ALLOCATE (eigval(ndf))
     215          879 :       eigval(:) = 0.0_dp
     216              : 
     217          879 :       CALL force_env_get(force_env=force_env, subsys=subsys)
     218          879 :       CALL cp_subsys_get(subsys, atomic_kinds=atomic_kinds)
     219          879 :       CALL get_atomic_kind_set(atomic_kind_set=atomic_kinds%els, shell_present=shell_present)
     220          879 :       IF (use_mod_hes) THEN
     221          757 :          IF (shell_present) THEN
     222              :             CALL cp_warn(__LOCATION__, &
     223              :                          "No model Hessian is available for core-shell models. "// &
     224            4 :                          "A unit matrix is used as the initial Hessian.")
     225            4 :             use_mod_hes = .FALSE.
     226              :          END IF
     227          757 :          IF (gopt_env%type_id == default_cell_method_id) THEN
     228              :             CALL cp_warn(__LOCATION__, &
     229              :                          "No model Hessian is available for cell optimizations. "// &
     230            0 :                          "A unit matrix is used as the initial Hessian.")
     231            0 :             use_mod_hes = .FALSE.
     232              :          END IF
     233              :       END IF
     234              : 
     235          879 :       IF (use_mod_hes) THEN
     236          753 :          CALL cp_fm_set_all(hess_mat, alpha=zero)
     237          753 :          CALL construct_initial_hess(gopt_env%force_env, hess_mat)
     238          753 :          CALL cp_fm_to_fm(hess_mat, hess_tmp)
     239          753 :          CALL choose_eigv_solver(hess_tmp, eigvec_mat, eigval, info=info)
     240              :          ! In rare cases the diagonalization of hess_mat fails (bug in scalapack?)
     241          753 :          IF (info /= 0) THEN
     242            0 :             CALL cp_fm_set_all(hess_mat, alpha=zero, beta=one)
     243            0 :             IF (output_unit > 0) THEN
     244              :                WRITE (output_unit, *) &
     245            0 :                   "BFGS: Matrix diagonalization failed, using unity as model Hessian."
     246              :             END IF
     247              :          ELSE
     248        16389 :             DO its = 1, SIZE(eigval)
     249        16389 :                IF (eigval(its) < 0.1_dp) eigval(its) = 0.1_dp
     250              :             END DO
     251          753 :             CALL cp_fm_to_fm(eigvec_mat, hess_tmp)
     252          753 :             CALL cp_fm_column_scale(eigvec_mat, eigval)
     253          753 :             CALL parallel_gemm("N", "T", ndf, ndf, ndf, one, hess_tmp, eigvec_mat, zero, hess_mat)
     254              :          END IF
     255              :       ELSE
     256          126 :          CALL cp_fm_set_all(hess_mat, alpha=zero, beta=one)
     257              :       END IF
     258              : 
     259         2637 :       ALLOCATE (xold(ndf))
     260        23985 :       xold(:) = x0(:)
     261              : 
     262         1758 :       ALLOCATE (g(ndf))
     263        23985 :       g(:) = 0.0_dp
     264              : 
     265         1758 :       ALLOCATE (gold(ndf))
     266          879 :       gold(:) = 0.0_dp
     267              : 
     268         2637 :       ALLOCATE (dx(ndf))
     269          879 :       dx(:) = 0.0_dp
     270              : 
     271         2637 :       ALLOCATE (dg(ndf))
     272          879 :       dg(:) = 0.0_dp
     273              : 
     274         2637 :       ALLOCATE (work(ndf))
     275          879 :       work(:) = 0.0_dp
     276              : 
     277         2637 :       ALLOCATE (dr(ndf))
     278          879 :       dr(:) = 0.0_dp
     279              : 
     280              :       ! find space_group
     281          879 :       CALL section_vals_val_get(geo_section, "KEEP_SPACE_GROUP", l_val=spgr%keep_space_group)
     282          879 :       IF (spgr%keep_space_group) THEN
     283           12 :          CALL identify_space_group(subsys, geo_section, gopt_env, output_unit)
     284           12 :          CALL spgr_apply_rotations_coord(spgr, x0)
     285           12 :          CALL print_spgr(spgr)
     286              :       END IF
     287              : 
     288              :       ! Geometry optimization starts now
     289          879 :       CALL cp_iterate(logger%iter_info, increment=0, iter_nr_out=iter_nr)
     290          879 :       CALL print_geo_opt_header(gopt_env, output_unit, wildcard)
     291              : 
     292              :       ! Calculate Energy & Gradients
     293              :       CALL cp_eval_at(gopt_env, x0, etot, g, gopt_env%force_env%para_env%mepos, &
     294          879 :                       .FALSE., gopt_env%force_env%para_env)
     295              : 
     296              :       ! Symmetrize coordinates and forces
     297          879 :       IF (spgr%keep_space_group) THEN
     298           12 :          CALL spgr_apply_rotations_coord(spgr, x0)
     299           12 :          CALL spgr_apply_rotations_force(spgr, g)
     300              :       END IF
     301              : 
     302              :       ! Print info at time 0
     303          879 :       emin = etot
     304          879 :       t_now = m_walltime()
     305          879 :       t_diff = t_now - t_old
     306          879 :       t_old = t_now
     307          879 :       CALL gopt_f_io_init(gopt_env, output_unit, etot, wildcard=wildcard, its=iter_nr, used_time=t_diff)
     308         4160 :       DO its = iter_nr + 1, maxiter
     309         4150 :          CALL cp_iterate(logger%iter_info, last=(its == maxiter))
     310         4150 :          CALL section_vals_val_set(geo_section, "STEP_START_VAL", i_val=its)
     311         4150 :          CALL gopt_f_ii(its, output_unit)
     312              : 
     313              :          ! Hessian update/restarting
     314         4150 :          IF (((its - iter_nr) == 1) .AND. hesrest) THEN
     315            2 :             IF (ionode) THEN
     316            1 :                CALL section_vals_val_get(geo_section, "BFGS%RESTART_FILE_NAME", c_val=hes_filename)
     317            1 :                IF (LEN_TRIM(hes_filename) == 0) THEN
     318              :                   ! Set default Hessian restart file name if no file name is defined
     319            0 :                   hes_filename = TRIM(logger%iter_info%project_name)//"-BFGS.Hessian"
     320              :                END IF
     321            1 :                IF (output_unit > 0) THEN
     322              :                   WRITE (UNIT=output_unit, FMT="(/,T2,A)") &
     323            1 :                      "BFGS| Checking for Hessian restart file <"//TRIM(ADJUSTL(hes_filename))//">"
     324              :                END IF
     325              :                CALL open_file(file_name=TRIM(hes_filename), file_status="OLD", &
     326            1 :                               file_form="UNFORMATTED", file_action="READ", unit_number=hesunit_read)
     327            1 :                IF (output_unit > 0) THEN
     328              :                   WRITE (UNIT=output_unit, FMT="(T2,A)") &
     329            1 :                      "BFGS| Hessian restart file read"
     330              :                END IF
     331              :             END IF
     332            2 :             CALL cp_fm_read_unformatted(hess_mat, hesunit_read)
     333            2 :             IF (ionode) CALL close_file(unit_number=hesunit_read)
     334              :          ELSE
     335         4148 :             IF ((its - iter_nr) > 1) THEN
     336              :                ! Symmetrize old coordinates and old forces
     337         3281 :                IF (spgr%keep_space_group) THEN
     338            0 :                   CALL spgr_apply_rotations_coord(spgr, xold)
     339            0 :                   CALL spgr_apply_rotations_force(spgr, gold)
     340              :                END IF
     341              : 
     342       252596 :                DO indf = 1, ndf
     343       249315 :                   dx(indf) = x0(indf) - xold(indf)
     344       252596 :                   dg(indf) = g(indf) - gold(indf)
     345              :                END DO
     346              : 
     347         3281 :                CALL bfgs(ndf, dx, dg, hess_mat, work, para_env)
     348              : 
     349              :                ! Symmetrize coordinates and forces change
     350         3281 :                IF (spgr%keep_space_group) THEN
     351            0 :                   CALL spgr_apply_rotations_force(spgr, dx)
     352            0 :                   CALL spgr_apply_rotations_force(spgr, dg)
     353              :                END IF
     354              : 
     355              :                !Possibly dump the Hessian file
     356         3281 :                IF (BTEST(cp_print_key_should_output(logger%iter_info, print_key), cp_p_file)) THEN
     357         2655 :                   CALL write_bfgs_hessian(geo_section, hess_mat, logger)
     358              :                END IF
     359              :             END IF
     360              :          END IF
     361              : 
     362              :          ! Symmetrize coordinates and forces
     363         4150 :          IF (spgr%keep_space_group) THEN
     364           12 :             CALL spgr_apply_rotations_coord(spgr, x0)
     365           12 :             CALL spgr_apply_rotations_force(spgr, g)
     366              :          END IF
     367              : 
     368              :          ! Setting the present positions & gradients as old
     369       276427 :          xold(:) = x0
     370       276427 :          gold(:) = g
     371              : 
     372              :          ! Copying hessian hes to (ndf x ndf) matrix hes_mat for diagonalization
     373         4150 :          CALL cp_fm_to_fm(hess_mat, hess_tmp)
     374              : 
     375         4150 :          CALL choose_eigv_solver(hess_tmp, eigvec_mat, eigval, info=info)
     376              : 
     377              :          ! In rare cases the diagonalization of hess_mat fails (bug in scalapack?)
     378         4150 :          IF (info /= 0) THEN
     379            0 :             IF (output_unit > 0) THEN
     380              :                WRITE (output_unit, *) &
     381            0 :                   "BFGS: Matrix diagonalization failed, resetting Hessian to unity."
     382              :             END IF
     383            0 :             CALL cp_fm_set_all(hess_mat, alpha=zero, beta=one)
     384            0 :             CALL cp_fm_to_fm(hess_mat, hess_tmp)
     385            0 :             CALL choose_eigv_solver(hess_tmp, eigvec_mat, eigval)
     386              :          END IF
     387              : 
     388         4150 :          IF (use_rfo) THEN
     389          819 :             CALL set_hes_eig(ndf, eigval, work)
     390        78549 :             dx(:) = eigval
     391          819 :             CALL rat_fun_opt(ndf, dg, eigval, work, eigvec_mat, g, para_env)
     392              :          END IF
     393         4150 :          CALL geoopt_get_step(ndf, eigval, eigvec_mat, hess_tmp, dr, g, para_env, use_rfo)
     394              : 
     395              :          ! Symmetrize dr
     396         4150 :          IF (spgr%keep_space_group) THEN
     397           12 :             CALL spgr_apply_rotations_force(spgr, dr)
     398              :          END IF
     399              : 
     400         4150 :          CALL trust_radius(ndf, step, rad, rat, dr, output_unit)
     401              : 
     402              :          ! Update the atomic positions
     403       276427 :          x0 = x0 + dr
     404              : 
     405              :          ! Symmetrize coordinates
     406         4150 :          IF (spgr%keep_space_group) THEN
     407           12 :             CALL spgr_apply_rotations_coord(spgr, x0)
     408              :          END IF
     409              : 
     410         4150 :          CALL energy_predict(ndf, work, hess_mat, dr, g, conv, pred, para_env)
     411         4150 :          eold = etot
     412              : 
     413              :          ! Energy & Gradients at new step
     414              :          CALL cp_eval_at(gopt_env, x0, etot, g, gopt_env%force_env%para_env%mepos, &
     415         4150 :                          .FALSE., gopt_env%force_env%para_env)
     416              : 
     417         4150 :          ediff = etot - eold
     418              : 
     419              :          ! Symmetrize forces
     420         4150 :          IF (spgr%keep_space_group) THEN
     421           12 :             CALL spgr_apply_rotations_force(spgr, g)
     422              :          END IF
     423              : 
     424              :          ! check for an external exit command
     425         4150 :          CALL external_control(should_stop, "GEO", globenv=globenv)
     426         4150 :          IF (should_stop) EXIT
     427              : 
     428              :          ! Some IO and Convergence check
     429         4150 :          t_now = m_walltime()
     430         4150 :          t_diff = t_now - t_old
     431         4150 :          t_old = t_now
     432              :          CALL gopt_f_io(gopt_env, force_env, root_section, its, etot, output_unit, &
     433              :                         eold, emin, wildcard, gopt_param, ndf, dr, g, conv, pred, rat, &
     434         4150 :                         step, rad, used_time=t_diff)
     435              : 
     436         4150 :          IF (conv .OR. (its == maxiter)) EXIT
     437         3281 :          IF (etot < emin) emin = etot
     438        12460 :          IF (use_rfo) CALL update_trust_rad(rat, rad, step, ediff)
     439              :       END DO
     440              : 
     441          879 :       IF (its == maxiter .AND. (.NOT. conv)) THEN
     442          609 :          CALL print_geo_opt_nc(gopt_env, output_unit)
     443              :       END IF
     444              : 
     445              :       ! show space_group
     446          879 :       CALL section_vals_val_get(geo_section, "SHOW_SPACE_GROUP", l_val=spgr%show_space_group)
     447          879 :       IF (spgr%show_space_group) THEN
     448            2 :          CALL identify_space_group(subsys, geo_section, gopt_env, output_unit)
     449            2 :          CALL print_spgr(spgr)
     450              :       END IF
     451              : 
     452              :       ! Write final  information, if converged
     453          879 :       CALL cp_iterate(logger%iter_info, last=.TRUE., increment=0)
     454          879 :       CALL write_bfgs_hessian(geo_section, hess_mat, logger)
     455              :       CALL gopt_f_io_finalize(gopt_env, force_env, x0, conv, its, root_section, &
     456          879 :                               gopt_env%force_env%para_env, gopt_env%force_env%para_env%mepos, output_unit)
     457              : 
     458          879 :       CALL cp_fm_struct_release(fm_struct_hes)
     459          879 :       CALL cp_fm_release(hess_mat)
     460          879 :       CALL cp_fm_release(eigvec_mat)
     461          879 :       CALL cp_fm_release(hess_tmp)
     462              : 
     463          879 :       CALL cp_blacs_env_release(blacs_env)
     464          879 :       DEALLOCATE (xold)
     465          879 :       DEALLOCATE (g)
     466          879 :       DEALLOCATE (gold)
     467          879 :       DEALLOCATE (dx)
     468          879 :       DEALLOCATE (dg)
     469          879 :       DEALLOCATE (eigval)
     470          879 :       DEALLOCATE (work)
     471          879 :       DEALLOCATE (dr)
     472              : 
     473              :       CALL cp_print_key_finished_output(output_unit, logger, geo_section, &
     474          879 :                                         "PRINT%PROGRAM_RUN_INFO")
     475          879 :       CALL timestop(handle)
     476              : 
     477         5274 :    END SUBROUTINE geoopt_bfgs
     478              : 
     479              : ! **************************************************************************************************
     480              : !> \brief ...
     481              : !> \param ndf ...
     482              : !> \param dg ...
     483              : !> \param eigval ...
     484              : !> \param work ...
     485              : !> \param eigvec_mat ...
     486              : !> \param g ...
     487              : !> \param para_env ...
     488              : ! **************************************************************************************************
     489         1638 :    SUBROUTINE rat_fun_opt(ndf, dg, eigval, work, eigvec_mat, g, para_env)
     490              : 
     491              :       INTEGER, INTENT(IN)                                :: ndf
     492              :       REAL(KIND=dp), INTENT(INOUT)                       :: dg(ndf), eigval(ndf), work(ndf)
     493              :       TYPE(cp_fm_type), INTENT(IN)                       :: eigvec_mat
     494              :       REAL(KIND=dp), INTENT(INOUT)                       :: g(ndf)
     495              :       TYPE(mp_para_env_type), OPTIONAL, POINTER          :: para_env
     496              : 
     497              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'rat_fun_opt'
     498              :       REAL(KIND=dp), PARAMETER                           :: one = 1.0_dp
     499              : 
     500              :       INTEGER                                            :: handle, i, indf, iref, iter, j, k, l, &
     501              :                                                             maxit, ncol_local, nrow_local
     502          819 :       INTEGER, DIMENSION(:), POINTER                     :: col_indices, row_indices
     503              :       LOGICAL                                            :: bisec, fail, set, conv
     504              :       REAL(KIND=dp)                                      :: fun, fun1, fun2, fun3, fung, lam1, lam2, &
     505              :                                                             ln, lp, ssize, step, stol
     506          819 :       REAL(KIND=dp), CONTIGUOUS, DIMENSION(:, :), POINTER            :: local_data
     507              : 
     508          819 :       CALL timeset(routineN, handle)
     509              : 
     510          819 :       stol = 1.0E-8_dp
     511          819 :       ssize = 0.2_dp
     512          819 :       maxit = 999
     513          819 :       fail = .FALSE.
     514          819 :       bisec = .FALSE.
     515              : 
     516        78549 :       dg = 0._dp
     517              : 
     518              :       CALL cp_fm_get_info(eigvec_mat, row_indices=row_indices, col_indices=col_indices, &
     519          819 :                           local_data=local_data, nrow_local=nrow_local, ncol_local=ncol_local)
     520              : 
     521        49479 :       DO i = 1, nrow_local
     522        48660 :          j = row_indices(i)
     523     10885479 :          DO k = 1, ncol_local
     524     10836000 :             l = col_indices(k)
     525     10884660 :             dg(l) = dg(l) + local_data(i, k)*g(j)
     526              :          END DO
     527              :       END DO
     528          819 :       CALL para_env%sum(dg)
     529              : 
     530          819 :       set = .FALSE.
     531              : 
     532              :       DO
     533              : 
     534              : !   calculating Lambda
     535              : 
     536          819 :          lp = 0.0_dp
     537          819 :          iref = 1
     538          819 :          ln = 0.0_dp
     539          819 :          IF (eigval(iref) < 0.0_dp) ln = eigval(iref) - 0.01_dp
     540              : 
     541          819 :          conv = .FALSE.
     542          819 :          iter = 0
     543              :          DO
     544         2551 :             iter = iter + 1
     545         2551 :             fun = 0.0_dp
     546         2551 :             fung = 0.0_dp
     547       227521 :             DO indf = 1, ndf
     548       224970 :                fun = fun + dg(indf)**2/(ln - eigval(indf))
     549       227521 :                fung = fung - dg(indf)**2/(ln - eigval(indf)**2)
     550              :             END DO
     551         2551 :             fun = fun - ln
     552         2551 :             fung = fung - one
     553         2551 :             step = fun/fung
     554         2551 :             ln = ln - step
     555         2551 :             IF (ABS(step) < stol) THEN
     556              :                conv = .TRUE.
     557              :                EXIT
     558              :             END IF
     559         1732 :             IF (iter >= maxit) EXIT
     560              :          END DO
     561              :          outer: DO
     562          821 :             IF (.NOT. conv) THEN
     563           62 :                conv = .FALSE.
     564           62 :                bisec = .TRUE.
     565           62 :                iter = 0
     566           62 :                maxit = 9999
     567           62 :                lam1 = 0.0_dp
     568           62 :                IF (eigval(iref) < 0.0_dp) lam1 = eigval(iref) - 0.01_dp
     569              :                fun1 = 0.0_dp
     570           62 :                DO indf = 1, ndf
     571           62 :                   fun1 = fun1 + dg(indf)**2/(lam1 - eigval(indf))
     572              :                END DO
     573            2 :                fun1 = fun1 - lam1
     574            2 :                step = ABS(lam1)/1000.0_dp
     575              :                IF (step < ssize) step = ssize
     576              :                inner: DO
     577            2 :                   iter = iter + 1
     578            2 :                   IF (iter > maxit) THEN
     579              :                      ln = 0.0_dp
     580          819 :                      lp = 0.0_dp
     581              :                      fail = .TRUE.
     582              :                      EXIT outer
     583              :                   END IF
     584            2 :                   fun2 = 0.0_dp
     585            2 :                   lam2 = lam1 - iter*step
     586           62 :                   DO indf = 1, ndf
     587           62 :                      fun2 = fun2 + eigval(indf)**2/(lam2 - eigval(indf))
     588              :                   END DO
     589            2 :                   fun2 = fun2 - lam2
     590            2 :                   IF (fun2*fun1 < 0.0_dp) THEN
     591              :                      iter = 0
     592              :                      DO
     593           50 :                         iter = iter + 1
     594           50 :                         IF (iter > maxit) THEN
     595              :                            ln = 0.0_dp
     596              :                            lp = 0.0_dp
     597              :                            fail = .TRUE.
     598              :                            EXIT outer
     599              :                         END IF
     600           50 :                         step = (lam1 + lam2)/2
     601           50 :                         fun3 = 0.0_dp
     602         1550 :                         DO indf = 1, ndf
     603         1550 :                            fun3 = fun3 + dg(indf)**2/(step - eigval(indf))
     604              :                         END DO
     605           50 :                         fun3 = fun3 - step
     606              : 
     607           50 :                         IF (ABS(step - lam2) < stol) THEN
     608              :                            ln = step
     609              :                            EXIT inner
     610              :                         END IF
     611              : 
     612           48 :                         IF (fun3*fun1 < stol) THEN
     613              :                            lam2 = step
     614              :                         ELSE
     615           48 :                            lam1 = step
     616              :                         END IF
     617              :                      END DO
     618              :                   END IF
     619              :                END DO inner
     620              :             END IF
     621          821 :             IF ((ln > eigval(iref)) .OR. ((ln > 0.0_dp) .AND. &
     622              :                                           (eigval(iref) > 0.0_dp))) THEN
     623              : 
     624            2 :                IF (.NOT. bisec) THEN
     625              :                   conv = .FALSE.
     626              :                   CYCLE outer
     627              :                END IF
     628              :                ln = 0.0_dp
     629              :                lp = 0.0_dp
     630              :                fail = .TRUE.
     631              :             END IF
     632              :             EXIT outer
     633              :          END DO outer
     634              : 
     635          819 :          IF (fail .AND. .NOT. set) THEN
     636            0 :             set = .TRUE.
     637            0 :             DO indf = 1, ndf
     638            0 :                eigval(indf) = eigval(indf)*work(indf)
     639              :             END DO
     640              :             CYCLE
     641              :          END IF
     642              : 
     643          819 :          IF (.NOT. set) THEN
     644        78549 :             work(1:ndf) = one
     645              :          END IF
     646              : 
     647        78549 :          DO indf = 1, ndf
     648        78549 :             eigval(indf) = eigval(indf) - ln
     649              :          END DO
     650              :          EXIT
     651              :       END DO
     652              : 
     653          819 :       CALL timestop(handle)
     654              : 
     655          819 :    END SUBROUTINE rat_fun_opt
     656              : 
     657              : ! **************************************************************************************************
     658              : !> \brief ...
     659              : !> \param ndf ...
     660              : !> \param dx ...
     661              : !> \param dg ...
     662              : !> \param hess_mat ...
     663              : !> \param work ...
     664              : !> \param para_env ...
     665              : ! **************************************************************************************************
     666         6562 :    SUBROUTINE bfgs(ndf, dx, dg, hess_mat, work, para_env)
     667              :       INTEGER, INTENT(IN)                                :: ndf
     668              :       REAL(KIND=dp), INTENT(INOUT)                       :: dx(ndf), dg(ndf)
     669              :       TYPE(cp_fm_type), INTENT(IN)                       :: hess_mat
     670              :       REAL(KIND=dp), INTENT(INOUT)                       :: work(ndf)
     671              :       TYPE(mp_para_env_type), OPTIONAL, POINTER          :: para_env
     672              : 
     673              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'bfgs'
     674              :       REAL(KIND=dp), PARAMETER                           :: one = 1.0_dp, zero = 0.0_dp
     675              : 
     676              :       INTEGER                                            :: handle, i, j, k, l, ncol_local, &
     677              :                                                             nrow_local
     678         3281 :       INTEGER, DIMENSION(:), POINTER                     :: col_indices, row_indices
     679              :       REAL(KIND=dp)                                      :: DDOT, dxw, gdx
     680         3281 :       REAL(KIND=dp), CONTIGUOUS, DIMENSION(:, :), POINTER            :: local_hes
     681              : 
     682         3281 :       CALL timeset(routineN, handle)
     683              : 
     684              :       CALL cp_fm_get_info(hess_mat, row_indices=row_indices, col_indices=col_indices, &
     685         3281 :                           local_data=local_hes, nrow_local=nrow_local, ncol_local=ncol_local)
     686              : 
     687       252596 :       work = zero
     688       152297 :       DO i = 1, nrow_local
     689       149016 :          j = row_indices(i)
     690     22715009 :          DO k = 1, ncol_local
     691     22562712 :             l = col_indices(k)
     692     22711728 :             work(j) = work(j) + local_hes(i, k)*dx(l)
     693              :          END DO
     694              :       END DO
     695              : 
     696         3281 :       CALL para_env%sum(work)
     697              : 
     698         3281 :       gdx = DDOT(ndf, dg, 1, dx, 1)
     699         3281 :       gdx = one/gdx
     700         3281 :       dxw = DDOT(ndf, dx, 1, work, 1)
     701         3281 :       dxw = one/dxw
     702              : 
     703       152297 :       DO i = 1, nrow_local
     704       149016 :          j = row_indices(i)
     705     22715009 :          DO k = 1, ncol_local
     706     22562712 :             l = col_indices(k)
     707              :             local_hes(i, k) = local_hes(i, k) + gdx*dg(j)*dg(l) - &
     708     22711728 :                               dxw*work(j)*work(l)
     709              :          END DO
     710              :       END DO
     711              : 
     712         3281 :       CALL timestop(handle)
     713              : 
     714         3281 :    END SUBROUTINE bfgs
     715              : 
     716              : ! **************************************************************************************************
     717              : !> \brief ...
     718              : !> \param ndf ...
     719              : !> \param eigval ...
     720              : !> \param work ...
     721              : ! **************************************************************************************************
     722          819 :    SUBROUTINE set_hes_eig(ndf, eigval, work)
     723              :       INTEGER, INTENT(IN)                                :: ndf
     724              :       REAL(KIND=dp), INTENT(INOUT)                       :: eigval(ndf), work(ndf)
     725              : 
     726              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'set_hes_eig'
     727              :       REAL(KIND=dp), PARAMETER                           :: max_neg = -0.5_dp, max_pos = 5.0_dp, &
     728              :                                                             min_eig = 0.005_dp, one = 1.0_dp
     729              : 
     730              :       INTEGER                                            :: handle, indf
     731              :       LOGICAL                                            :: neg
     732              : 
     733          819 :       CALL timeset(routineN, handle)
     734              : 
     735        78549 :       DO indf = 1, ndf
     736        77730 :          IF (eigval(indf) < 0.0_dp) neg = .TRUE.
     737        78549 :          IF (eigval(indf) > 1000.0_dp) eigval(indf) = 1000.0_dp
     738              :       END DO
     739        78549 :       DO indf = 1, ndf
     740        78549 :          IF (eigval(indf) < 0.0_dp) THEN
     741            2 :             IF (eigval(indf) < max_neg) THEN
     742            0 :                eigval(indf) = max_neg
     743            2 :             ELSE IF (eigval(indf) > -min_eig) THEN
     744            1 :                eigval(indf) = -min_eig
     745              :             END IF
     746        77728 :          ELSE IF (eigval(indf) < 1000.0_dp) THEN
     747        77728 :             IF (eigval(indf) < min_eig) THEN
     748          321 :                eigval(indf) = min_eig
     749        77407 :             ELSE IF (eigval(indf) > max_pos) THEN
     750            0 :                eigval(indf) = max_pos
     751              :             END IF
     752              :          END IF
     753              :       END DO
     754              : 
     755        78549 :       DO indf = 1, ndf
     756        78549 :          IF (eigval(indf) < 0.0_dp) THEN
     757            2 :             work(indf) = -one
     758              :          ELSE
     759        77728 :             work(indf) = one
     760              :          END IF
     761              :       END DO
     762              : 
     763          819 :       CALL timestop(handle)
     764              : 
     765          819 :    END SUBROUTINE set_hes_eig
     766              : 
     767              : ! **************************************************************************************************
     768              : !> \brief ...
     769              : !> \param ndf ...
     770              : !> \param eigval ...
     771              : !> \param eigvec_mat ...
     772              : !> \param hess_tmp ...
     773              : !> \param dr ...
     774              : !> \param g ...
     775              : !> \param para_env ...
     776              : !> \param use_rfo ...
     777              : ! **************************************************************************************************
     778        12450 :    SUBROUTINE geoopt_get_step(ndf, eigval, eigvec_mat, hess_tmp, dr, g, para_env, use_rfo)
     779              : 
     780              :       INTEGER, INTENT(IN)                                :: ndf
     781              :       REAL(KIND=dp), INTENT(INOUT)                       :: eigval(ndf)
     782              :       TYPE(cp_fm_type), INTENT(IN)                       :: eigvec_mat, hess_tmp
     783              :       REAL(KIND=dp), INTENT(INOUT)                       :: dr(ndf), g(ndf)
     784              :       TYPE(mp_para_env_type), OPTIONAL, POINTER          :: para_env
     785              :       LOGICAL                                            :: use_rfo
     786              : 
     787              :       REAL(KIND=dp), PARAMETER                           :: one = 1.0_dp, zero = 0.0_dp
     788              : 
     789              :       INTEGER                                            :: i, indf, j, k, l, ncol_local, nrow_local
     790         4150 :       INTEGER, DIMENSION(:), POINTER                     :: col_indices, row_indices
     791         4150 :       REAL(KIND=dp), CONTIGUOUS, DIMENSION(:, :), POINTER            :: local_data
     792              :       TYPE(cp_fm_struct_type), POINTER                   :: matrix_struct
     793              :       TYPE(cp_fm_type)                          :: tmp
     794              : 
     795         4150 :       CALL cp_fm_to_fm(eigvec_mat, hess_tmp)
     796         4150 :       IF (use_rfo) THEN
     797        78549 :          DO indf = 1, ndf
     798        78549 :             eigval(indf) = one/eigval(indf)
     799              :          END DO
     800              :       ELSE
     801       197878 :          DO indf = 1, ndf
     802       197878 :             eigval(indf) = one/MAX(0.0001_dp, eigval(indf))
     803              :          END DO
     804              :       END IF
     805              : 
     806         4150 :       CALL cp_fm_column_scale(hess_tmp, eigval)
     807         4150 :       CALL cp_fm_get_info(eigvec_mat, matrix_struct=matrix_struct)
     808         4150 :       CALL cp_fm_create(tmp, matrix_struct, name="tmp")
     809         4150 :       CALL cp_fm_set_all(tmp, alpha=zero)
     810              : 
     811         4150 :       CALL parallel_gemm("N", "T", ndf, ndf, ndf, one, hess_tmp, eigvec_mat, zero, tmp)
     812              : 
     813         4150 :       CALL cp_fm_transpose(tmp, hess_tmp)
     814         4150 :       CALL cp_fm_release(tmp)
     815              : 
     816              :       ! New step
     817              : 
     818              :       CALL cp_fm_get_info(hess_tmp, row_indices=row_indices, col_indices=col_indices, &
     819         4150 :                           local_data=local_data, nrow_local=nrow_local, ncol_local=ncol_local)
     820              : 
     821       276427 :       dr = 0.0_dp
     822       166582 :       DO i = 1, nrow_local
     823       162432 :          j = row_indices(i)
     824     24428656 :          DO k = 1, ncol_local
     825     24262074 :             l = col_indices(k)
     826     24424506 :             dr(j) = dr(j) - local_data(i, k)*g(l)
     827              :          END DO
     828              :       END DO
     829              : 
     830         4150 :       CALL para_env%sum(dr)
     831              : 
     832         4150 :    END SUBROUTINE geoopt_get_step
     833              : 
     834              : ! **************************************************************************************************
     835              : !> \brief ...
     836              : !> \param ndf ...
     837              : !> \param step ...
     838              : !> \param rad ...
     839              : !> \param rat ...
     840              : !> \param dr ...
     841              : !> \param output_unit ...
     842              : ! **************************************************************************************************
     843         4150 :    SUBROUTINE trust_radius(ndf, step, rad, rat, dr, output_unit)
     844              :       INTEGER, INTENT(IN)                                :: ndf
     845              :       REAL(KIND=dp), INTENT(INOUT)                       :: step, rad, rat, dr(ndf)
     846              :       INTEGER, INTENT(IN)                                :: output_unit
     847              : 
     848              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'trust_radius'
     849              :       REAL(KIND=dp), PARAMETER                           :: one = 1.0_dp
     850              : 
     851              :       INTEGER                                            :: handle
     852              :       REAL(KIND=dp)                                      :: scal
     853              : 
     854         4150 :       CALL timeset(routineN, handle)
     855              : 
     856       276427 :       step = MAXVAL(ABS(dr))
     857         4150 :       scal = MAX(one, rad/step)
     858              : 
     859         4150 :       IF (step > rad) THEN
     860          372 :          rat = rad/step
     861          372 :          CALL DSCAL(ndf, rat, dr, 1)
     862          372 :          step = rad
     863          372 :          IF (output_unit > 0) THEN
     864              :             WRITE (unit=output_unit, FMT="(/,T2,A,F8.5)") &
     865          189 :                " Step is scaled; Scaling factor = ", rat
     866          189 :             CALL m_flush(output_unit)
     867              :          END IF
     868              :       END IF
     869         4150 :       CALL timestop(handle)
     870              : 
     871         4150 :    END SUBROUTINE trust_radius
     872              : 
     873              : ! **************************************************************************************************
     874              : !> \brief ...
     875              : !> \param ndf ...
     876              : !> \param work ...
     877              : !> \param hess_mat ...
     878              : !> \param dr ...
     879              : !> \param g ...
     880              : !> \param conv ...
     881              : !> \param pred ...
     882              : !> \param para_env ...
     883              : ! **************************************************************************************************
     884         8300 :    SUBROUTINE energy_predict(ndf, work, hess_mat, dr, g, conv, pred, para_env)
     885              : 
     886              :       INTEGER, INTENT(IN)                                :: ndf
     887              :       REAL(KIND=dp), INTENT(INOUT)                       :: work(ndf)
     888              :       TYPE(cp_fm_type), INTENT(IN)                           :: hess_mat
     889              :       REAL(KIND=dp), INTENT(INOUT)                       :: dr(ndf), g(ndf)
     890              :       LOGICAL, INTENT(INOUT)                             :: conv
     891              :       REAL(KIND=dp), INTENT(INOUT)                       :: pred
     892              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     893              : 
     894              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'energy_predict'
     895              :       REAL(KIND=dp), PARAMETER                           :: zero = 0.0_dp
     896              : 
     897              :       INTEGER                                            :: handle, i, j, k, l, ncol_local, &
     898              :                                                             nrow_local
     899         4150 :       INTEGER, DIMENSION(:), POINTER                     :: col_indices, row_indices
     900              :       REAL(KIND=dp)                                      :: DDOT, ener1, ener2
     901         4150 :       REAL(KIND=dp), CONTIGUOUS, DIMENSION(:, :), POINTER            :: local_data
     902              : 
     903         4150 :       CALL timeset(routineN, handle)
     904              : 
     905         4150 :       ener1 = DDOT(ndf, g, 1, dr, 1)
     906              : 
     907              :       CALL cp_fm_get_info(hess_mat, row_indices=row_indices, col_indices=col_indices, &
     908         4150 :                           local_data=local_data, nrow_local=nrow_local, ncol_local=ncol_local)
     909              : 
     910       276427 :       work = zero
     911       166582 :       DO i = 1, nrow_local
     912       162432 :          j = row_indices(i)
     913     24428656 :          DO k = 1, ncol_local
     914     24262074 :             l = col_indices(k)
     915     24424506 :             work(j) = work(j) + local_data(i, k)*dr(l)
     916              :          END DO
     917              :       END DO
     918              : 
     919         4150 :       CALL para_env%sum(work)
     920         4150 :       ener2 = DDOT(ndf, dr, 1, work, 1)
     921         4150 :       pred = ener1 + 0.5_dp*ener2
     922         4150 :       conv = .FALSE.
     923         4150 :       CALL timestop(handle)
     924              : 
     925         4150 :    END SUBROUTINE energy_predict
     926              : 
     927              : ! **************************************************************************************************
     928              : !> \brief ...
     929              : !> \param rat ...
     930              : !> \param rad ...
     931              : !> \param step ...
     932              : !> \param ediff ...
     933              : ! **************************************************************************************************
     934          782 :    SUBROUTINE update_trust_rad(rat, rad, step, ediff)
     935              : 
     936              :       REAL(KIND=dp), INTENT(INOUT)                       :: rat, rad, step, ediff
     937              : 
     938              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'update_trust_rad'
     939              :       REAL(KIND=dp), PARAMETER                           :: max_trust = 1.0_dp, min_trust = 0.1_dp
     940              : 
     941              :       INTEGER                                            :: handle
     942              : 
     943          782 :       CALL timeset(routineN, handle)
     944              : 
     945          782 :       IF (rat > 4.0_dp) THEN
     946            0 :          IF (ediff < 0.0_dp) THEN
     947            0 :             rad = step*0.5_dp
     948              :          ELSE
     949            0 :             rad = step*0.25_dp
     950              :          END IF
     951          782 :       ELSE IF (rat > 2.0_dp) THEN
     952            0 :          IF (ediff < 0.0_dp) THEN
     953            0 :             rad = step*0.75_dp
     954              :          ELSE
     955            0 :             rad = step*0.5_dp
     956              :          END IF
     957          782 :       ELSE IF (rat > 4.0_dp/3.0_dp) THEN
     958            0 :          IF (ediff < 0.0_dp) THEN
     959            0 :             rad = step
     960              :          ELSE
     961            0 :             rad = step*0.75_dp
     962              :          END IF
     963          782 :       ELSE IF (rat > 10.0_dp/9.0_dp) THEN
     964            0 :          IF (ediff < 0.0_dp) THEN
     965            0 :             rad = step*1.25_dp
     966              :          ELSE
     967            0 :             rad = step
     968              :          END IF
     969          782 :       ELSE IF (rat > 0.9_dp) THEN
     970           64 :          IF (ediff < 0.0_dp) THEN
     971           63 :             rad = step*1.5_dp
     972              :          ELSE
     973            1 :             rad = step*1.25_dp
     974              :          END IF
     975          718 :       ELSE IF (rat > 0.75_dp) THEN
     976          115 :          IF (ediff < 0.0_dp) THEN
     977          112 :             rad = step*1.25_dp
     978              :          ELSE
     979            3 :             rad = step
     980              :          END IF
     981          603 :       ELSE IF (rat > 0.5_dp) THEN
     982           85 :          IF (ediff < 0.0_dp) THEN
     983           85 :             rad = step
     984              :          ELSE
     985            0 :             rad = step*0.75_dp
     986              :          END IF
     987          518 :       ELSE IF (rat > 0.25_dp) THEN
     988            5 :          IF (ediff < 0.0_dp) THEN
     989            5 :             rad = step*0.75_dp
     990              :          ELSE
     991            0 :             rad = step*0.5_dp
     992              :          END IF
     993          513 :       ELSE IF (ediff < 0.0_dp) THEN
     994          509 :          rad = step*0.5_dp
     995              :       ELSE
     996            4 :          rad = step*0.25_dp
     997              :       END IF
     998              : 
     999          782 :       rad = MAX(rad, min_trust)
    1000          782 :       rad = MIN(rad, max_trust)
    1001          782 :       CALL timestop(handle)
    1002              : 
    1003          782 :    END SUBROUTINE update_trust_rad
    1004              : 
    1005              : ! **************************************************************************************************
    1006              : 
    1007              : ! **************************************************************************************************
    1008              : !> \brief ...
    1009              : !> \param geo_section ...
    1010              : !> \param hess_mat ...
    1011              : !> \param logger ...
    1012              : ! **************************************************************************************************
    1013         3534 :    SUBROUTINE write_bfgs_hessian(geo_section, hess_mat, logger)
    1014              : 
    1015              :       TYPE(section_vals_type), POINTER                   :: geo_section
    1016              :       TYPE(cp_fm_type), INTENT(IN)                          :: hess_mat
    1017              :       TYPE(cp_logger_type), POINTER                      :: logger
    1018              : 
    1019              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'write_bfgs_hessian'
    1020              : 
    1021              :       INTEGER                                            :: handle, hesunit
    1022              : 
    1023         3534 :       CALL timeset(routineN, handle)
    1024              : 
    1025              :       hesunit = cp_print_key_unit_nr(logger, geo_section, "BFGS%RESTART", &
    1026              :                                      extension=".Hessian", file_form="UNFORMATTED", file_action="WRITE", &
    1027         3534 :                                      file_position="REWIND")
    1028              : 
    1029         3534 :       CALL cp_fm_write_unformatted(hess_mat, hesunit)
    1030              : 
    1031         3534 :       CALL cp_print_key_finished_output(hesunit, logger, geo_section, "BFGS%RESTART")
    1032              : 
    1033         3534 :       CALL timestop(handle)
    1034              : 
    1035         3534 :    END SUBROUTINE write_bfgs_hessian
    1036              : 
    1037              : ! **************************************************************************************************
    1038              : !> \brief Constructs model Hessian as described in https://doi.org/10.1016/0009-2614(95)00646-L.
    1039              : !> \param force_env ...
    1040              : !> \param hess_mat ...
    1041              : !> \author Florian Schiffmann
    1042              : ! **************************************************************************************************
    1043          753 :    SUBROUTINE construct_initial_hess(force_env, hess_mat)
    1044              : 
    1045              :       TYPE(force_env_type), POINTER                      :: force_env
    1046              :       TYPE(cp_fm_type), INTENT(IN)                          :: hess_mat
    1047              : 
    1048              :       INTEGER                                            :: i, iat_col, iat_row, iglobal, iind, j, &
    1049              :                                                             jat_row, jglobal, jind, k, natom, &
    1050              :                                                             ncol_local, nrow_local, z
    1051          753 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: at_row
    1052          753 :       INTEGER, DIMENSION(:), POINTER                     :: col_indices, row_indices
    1053              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: d_ij, rho_ij
    1054              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: r_ij
    1055              :       REAL(KIND=dp), DIMENSION(3, 3)                     :: alpha, r0
    1056          753 :       REAL(KIND=dp), CONTIGUOUS, DIMENSION(:, :), POINTER            :: fixed, local_data
    1057              :       TYPE(cell_type), POINTER                           :: cell
    1058              :       TYPE(cp_subsys_type), POINTER                      :: subsys
    1059              :       TYPE(particle_list_type), POINTER                  :: particles
    1060              : 
    1061          753 :       CALL cite_reference(Lindh1995)
    1062              : 
    1063          753 :       CALL force_env_get(force_env=force_env, subsys=subsys, cell=cell)
    1064              :       CALL cp_subsys_get(subsys, &
    1065          753 :                          particles=particles)
    1066              : 
    1067         3012 :       alpha(1, :) = [1._dp, 0.3949_dp, 0.3949_dp]
    1068         3012 :       alpha(2, :) = [0.3494_dp, 0.2800_dp, 0.2800_dp]
    1069         3012 :       alpha(3, :) = [0.3494_dp, 0.2800_dp, 0.1800_dp]
    1070              : 
    1071         3012 :       r0(1, :) = [1.35_dp, 2.10_dp, 2.53_dp]
    1072         3012 :       r0(2, :) = [2.10_dp, 2.87_dp, 3.40_dp]
    1073         3012 :       r0(3, :) = [2.53_dp, 3.40_dp, 3.40_dp]
    1074              : 
    1075              :       CALL cp_fm_get_info(hess_mat, row_indices=row_indices, col_indices=col_indices, &
    1076          753 :                           local_data=local_data, nrow_local=nrow_local, ncol_local=ncol_local)
    1077          753 :       natom = particles%n_els
    1078         2259 :       ALLOCATE (at_row(natom))
    1079         3012 :       ALLOCATE (rho_ij(natom, natom))
    1080         2259 :       ALLOCATE (d_ij(natom, natom))
    1081         3765 :       ALLOCATE (r_ij(natom, natom, 3))
    1082         2259 :       ALLOCATE (fixed(3, natom))
    1083        21601 :       fixed = 1.0_dp
    1084          753 :       CALL fix_atom_control(force_env, fixed)
    1085         3012 :       DO i = 1, 3
    1086        34284 :          CALL hess_mat%matrix_struct%para_env%min(fixed(i, :))
    1087              :       END DO
    1088          753 :       rho_ij = 0
    1089              :       !XXXX insert proper rows !XXX
    1090         5965 :       at_row = 3
    1091         5965 :       DO i = 1, natom
    1092         5212 :          CALL get_atomic_kind(atomic_kind=particles%els(i)%atomic_kind, z=z)
    1093         5212 :          IF (z <= 10) at_row(i) = 2
    1094        11177 :          IF (z <= 2) at_row(i) = 1
    1095              :       END DO
    1096         5212 :       DO i = 2, natom
    1097         4459 :          iat_row = at_row(i)
    1098        64249 :          DO j = 1, i - 1
    1099        59037 :             jat_row = at_row(j)
    1100              :             !pbc for a distance vector
    1101       236148 :             r_ij(j, i, :) = pbc(particles%els(i)%r, particles%els(j)%r, cell)
    1102       236148 :             r_ij(i, j, :) = -r_ij(j, i, :)
    1103       236148 :             d_ij(j, i) = NORM2(r_ij(j, i, :))
    1104        59037 :             d_ij(i, j) = d_ij(j, i)
    1105        59037 :             rho_ij(j, i) = EXP(alpha(jat_row, iat_row)*(r0(jat_row, iat_row)**2 - d_ij(j, i)**2))
    1106        63496 :             rho_ij(i, j) = rho_ij(j, i)
    1107              :          END DO
    1108              :       END DO
    1109        16389 :       DO i = 1, ncol_local
    1110        15636 :          iglobal = col_indices(i)
    1111        15636 :          iind = MOD(iglobal - 1, 3) + 1
    1112        15636 :          iat_col = (iglobal + 2)/3
    1113        15636 :          IF (iat_col > natom) CYCLE
    1114       661356 :          DO j = 1, nrow_local
    1115       644967 :             jglobal = row_indices(j)
    1116       644967 :             jind = MOD(jglobal - 1, 3) + 1
    1117       644967 :             iat_row = (jglobal + 2)/3
    1118       644967 :             IF (iat_row > natom) CYCLE
    1119       644967 :             IF (iat_row /= iat_col) THEN
    1120       615708 :                IF (d_ij(iat_row, iat_col) < 6.0_dp) THEN
    1121              :                   local_data(j, i) = local_data(j, i) + &
    1122       216612 :                                      angle_second_deriv(r_ij, d_ij, rho_ij, iind, jind, iat_col, iat_row, natom)
    1123              :                END IF
    1124              :             ELSE
    1125              :                local_data(j, i) = local_data(j, i) + &
    1126        29259 :                                   angle_second_deriv(r_ij, d_ij, rho_ij, iind, jind, iat_col, iat_row, natom)
    1127              :             END IF
    1128       644967 :             IF (iat_col /= iat_row) THEN
    1129       615708 :                IF (d_ij(iat_row, iat_col) < 6.0_dp) THEN
    1130              :                   local_data(j, i) = local_data(j, i) - &
    1131              :                                      dist_second_deriv(r_ij(iat_col, iat_row, :), &
    1132       866448 :                                                        iind, jind, d_ij(iat_row, iat_col), rho_ij(iat_row, iat_col))
    1133              :                END IF
    1134              :             ELSE
    1135       674226 :                DO k = 1, natom
    1136       644967 :                   IF (k == iat_col) CYCLE
    1137       644967 :                   IF (d_ij(iat_row, k) < 6.0_dp) THEN
    1138              :                      local_data(j, i) = local_data(j, i) + &
    1139              :                                         dist_second_deriv(r_ij(iat_col, k, :), &
    1140       866448 :                                                           iind, jind, d_ij(iat_row, k), rho_ij(iat_row, k))
    1141              :                   END IF
    1142              :                END DO
    1143              :             END IF
    1144       660603 :             IF (fixed(jind, iat_row) < 0.5_dp .OR. fixed(iind, iat_col) < 0.5_dp) THEN
    1145        10161 :                local_data(j, i) = 0.0_dp
    1146        10161 :                IF (jind == iind .AND. iat_row == iat_col) local_data(j, i) = 1.0_dp
    1147              :             END IF
    1148              :          END DO
    1149              :       END DO
    1150          753 :       DEALLOCATE (fixed)
    1151          753 :       DEALLOCATE (rho_ij)
    1152          753 :       DEALLOCATE (d_ij)
    1153          753 :       DEALLOCATE (r_ij)
    1154          753 :       DEALLOCATE (at_row)
    1155              : 
    1156         1506 :    END SUBROUTINE construct_initial_hess
    1157              : 
    1158              : ! **************************************************************************************************
    1159              : !> \brief ...
    1160              : !> \param r1 ...
    1161              : !> \param i ...
    1162              : !> \param j ...
    1163              : !> \param d ...
    1164              : !> \param rho ...
    1165              : !> \return ...
    1166              : ! **************************************************************************************************
    1167       433224 :    PURE FUNCTION dist_second_deriv(r1, i, j, d, rho) RESULT(deriv)
    1168              :       REAL(KIND=dp), DIMENSION(3), INTENT(IN)            :: r1
    1169              :       INTEGER, INTENT(IN)                                :: i, j
    1170              :       REAL(KIND=dp), INTENT(IN)                          :: d, rho
    1171              :       REAL(KIND=dp)                                      :: deriv
    1172              : 
    1173       433224 :       deriv = 0.45_dp*rho*(r1(i)*r1(j))/d**2
    1174       433224 :    END FUNCTION dist_second_deriv
    1175              : 
    1176              : ! **************************************************************************************************
    1177              : !> \brief ...
    1178              : !> \param r_ij ...
    1179              : !> \param d_ij ...
    1180              : !> \param rho_ij ...
    1181              : !> \param idir ...
    1182              : !> \param jdir ...
    1183              : !> \param iat_der ...
    1184              : !> \param jat_der ...
    1185              : !> \param natom ...
    1186              : !> \return ...
    1187              : ! **************************************************************************************************
    1188       245871 :    FUNCTION angle_second_deriv(r_ij, d_ij, rho_ij, idir, jdir, iat_der, jat_der, natom) RESULT(deriv)
    1189              :       REAL(KIND=dp), DIMENSION(:, :, :)                  :: r_ij
    1190              :       REAL(KIND=dp), DIMENSION(:, :)                     :: d_ij, rho_ij
    1191              :       INTEGER                                            :: idir, jdir, iat_der, jat_der, natom
    1192              :       REAL(KIND=dp)                                      :: deriv
    1193              : 
    1194              :       INTEGER                                            :: i, iat, idr, j, jat, jdr
    1195              :       REAL(KIND=dp)                                      :: d12, d23, d31, D_mat(3, 2), denom1, &
    1196              :                                                             denom2, denom3, ka1, ka2, ka3, rho12, &
    1197              :                                                             rho23, rho31, rsst1, rsst2, rsst3
    1198              :       REAL(KIND=dp), DIMENSION(3)                        :: r12, r23, r31
    1199              : 
    1200       245871 :       deriv = 0._dp
    1201       245871 :       IF (iat_der == jat_der) THEN
    1202       644967 :          DO i = 1, natom - 1
    1203       615708 :             IF (rho_ij(iat_der, i) < 0.00001) CYCLE
    1204      3404826 :             DO j = i + 1, natom
    1205      3180348 :                IF (rho_ij(iat_der, j) < 0.00001) CYCLE
    1206       944388 :                IF (i == iat_der .OR. j == iat_der) CYCLE
    1207       944388 :                IF (iat_der < i .OR. iat_der > j) THEN
    1208      5755410 :                   r12 = r_ij(iat_der, i, :); r23 = r_ij(i, j, :); r31 = r_ij(j, iat_der, :)
    1209       575541 :                   d12 = d_ij(iat_der, i); d23 = d_ij(i, j); d31 = d_ij(j, iat_der)
    1210       575541 :                   rho12 = rho_ij(iat_der, i); rho23 = rho_ij(i, j); rho31 = rho_ij(j, iat_der)
    1211              :                ELSE
    1212      3688470 :                   r12 = r_ij(iat_der, j, :); r23 = r_ij(j, i, :); r31 = r_ij(i, iat_der, :)
    1213       368847 :                   d12 = d_ij(iat_der, j); d23 = d_ij(j, i); d31 = d_ij(i, iat_der)
    1214       368847 :                   rho12 = rho_ij(iat_der, j); rho23 = rho_ij(j, i); rho31 = rho_ij(i, iat_der)
    1215              :                END IF
    1216       944388 :                ka1 = 0.15_dp*rho12*rho23; ka2 = 0.15_dp*rho23*rho31; ka3 = 0.15_dp*rho31*rho12
    1217      9443880 :                rsst1 = DOT_PRODUCT(r12, r23); rsst2 = DOT_PRODUCT(r23, r31); rsst3 = DOT_PRODUCT(r31, r12)
    1218       944388 :                denom1 = 1.0_dp - rsst1**2/(d12**2*d23**2); denom2 = 1.0_dp - rsst2**2/(d23**2*d31**2)
    1219       944388 :                denom3 = 1.0_dp - rsst3**2/(d31**2*d12**2)
    1220       944388 :                denom1 = SIGN(1.0_dp, denom1)*MAX(ABS(denom1), 0.01_dp)
    1221       944388 :                denom2 = SIGN(1.0_dp, denom2)*MAX(ABS(denom2), 0.01_dp)
    1222       944388 :                denom3 = SIGN(1.0_dp, denom3)*MAX(ABS(denom3), 0.01_dp)
    1223       944388 :                D_mat(1, 1) = r23(idir)/(d12*d23) - rsst1*r12(idir)/(d12**3*d23)
    1224       944388 :                D_mat(1, 2) = r23(jdir)/(d12*d23) - rsst1*r12(jdir)/(d12**3*d23)
    1225       944388 :                D_mat(2, 1) = -r23(idir)/(d23*d31) + rsst2*r31(idir)/(d23*d31**3)
    1226       944388 :                D_mat(2, 2) = -r23(jdir)/(d23*d31) + rsst2*r31(jdir)/(d23*d31**3)
    1227              :                D_mat(3, 1) = (r31(idir) - r12(idir))/(d31*d12) + rsst3*r31(idir)/(d31**3*d12) - &
    1228       944388 :                              rsst3*r12(idir)/(d31*d12**3)
    1229              :                D_mat(3, 2) = (r31(jdir) - r12(jdir))/(d31*d12) + rsst3*r31(jdir)/(d31**3*d12) - &
    1230       944388 :                              rsst3*r12(jdir)/(d31*d12**3)
    1231       944388 :                IF (ABS(denom1) <= 0.011_dp) D_mat(1, 1) = 0.0_dp
    1232       944388 :                IF (ABS(denom2) <= 0.011_dp) D_mat(2, 1) = 0.0_dp
    1233       944388 :                IF (ABS(denom3) <= 0.011_dp) D_mat(3, 1) = 0.0_dp
    1234              :                deriv = deriv + ka1*D_mat(1, 1)*D_mat(1, 2)/denom1 + &
    1235              :                        ka2*D_mat(2, 1)*D_mat(2, 2)/denom2 + &
    1236      3796056 :                        ka3*D_mat(3, 1)*D_mat(3, 2)/denom3
    1237              : 
    1238              :             END DO
    1239              :          END DO
    1240              :       ELSE
    1241      6115032 :          DO i = 1, natom
    1242      5898420 :             IF (i == iat_der .OR. i == jat_der) CYCLE
    1243      5465196 :             IF (jat_der < iat_der) THEN
    1244      2732598 :                iat = jat_der; jat = iat_der; idr = jdir; jdr = idir
    1245              :             ELSE
    1246      2732598 :                iat = iat_der; jat = jat_der; idr = idir; jdr = jdir
    1247              :             END IF
    1248      5465196 :             IF (jat < i .OR. iat > i) THEN
    1249     43193340 :                r12 = r_ij(iat, jat, :); r23 = r_ij(jat, i, :); r31 = r_ij(i, iat, :)
    1250      4319334 :                d12 = d_ij(iat, jat); d23 = d_ij(jat, i); d31 = d_ij(i, iat)
    1251      4319334 :                rho12 = rho_ij(iat, jat); rho23 = rho_ij(jat, i); rho31 = rho_ij(i, iat)
    1252              :             ELSE
    1253     11458620 :                r12 = r_ij(iat, i, :); r23 = r_ij(i, jat, :); r31 = r_ij(jat, iat, :)
    1254      1145862 :                d12 = d_ij(iat, i); d23 = d_ij(i, jat); d31 = d_ij(jat, iat)
    1255      1145862 :                rho12 = rho_ij(iat, i); rho23 = rho_ij(i, jat); rho31 = rho_ij(jat, iat)
    1256              :             END IF
    1257      5465196 :             ka1 = 0.15_dp*rho12*rho23; ka2 = 0.15_dp*rho23*rho31; ka3 = 0.15_dp*rho31*rho12
    1258     54651960 :             rsst1 = DOT_PRODUCT(r12, r23); rsst2 = DOT_PRODUCT(r23, r31); rsst3 = DOT_PRODUCT(r31, r12)
    1259      5465196 :             denom1 = 1.0_dp - rsst1**2/(d12**2*d23**2); denom2 = 1.0_dp - rsst2**2/(d23**2*d31**2)
    1260      5465196 :             denom3 = 1.0_dp - rsst3**2/(d31**2*d12**2)
    1261      5465196 :             denom1 = SIGN(1.0_dp, denom1)*MAX(ABS(denom1), 0.01_dp)
    1262      5465196 :             denom2 = SIGN(1.0_dp, denom2)*MAX(ABS(denom2), 0.01_dp)
    1263      5465196 :             denom3 = SIGN(1.0_dp, denom3)*MAX(ABS(denom3), 0.01_dp)
    1264      5465196 :             D_mat(1, 1) = r23(idr)/(d12*d23) - rsst1*r12(idr)/(d12**3*d23)
    1265      5465196 :             D_mat(2, 1) = -r23(idr)/(d23*d31) + rsst2*r31(idr)/(d23*d31**3)
    1266              :             D_mat(3, 1) = (r31(idr) - r12(idr))/(d31*d12) + rsst3*r31(idr)/(d31**3*d12) - &
    1267      5465196 :                           rsst3*r12(idr)/(d31*d12**3)
    1268      5465196 :             IF (jat < i .OR. iat > i) THEN
    1269              :                D_mat(1, 2) = (r12(jdr) - r23(jdr))/(d12*d23) + rsst1*r12(jdr)/(d12**3*d23) - &
    1270      4319334 :                              rsst1*r23(jdr)/(d12*d23**3)
    1271      4319334 :                D_mat(2, 2) = r31(jdr)/(d23*d31) - rsst2*r23(jdr)/(d23**3*d31)
    1272      4319334 :                D_mat(3, 2) = -r31(jdr)/(d31*d12) + rsst3*r12(jdr)/(d31*d12**3)
    1273              :             ELSE
    1274      1145862 :                D_mat(1, 2) = -r12(jdr)/(d12*d23) + rsst1*r23(jdr)/(d12*d23**3)
    1275              :                D_mat(2, 2) = (r23(jdr) - r31(jdr))/(d23*d31) + rsst2*r23(jdr)/(d23**3*d31) - &
    1276      1145862 :                              rsst2*r31(jdr)/(d23*d31**3)
    1277      1145862 :                D_mat(3, 2) = r12(jdr)/(d31*d12) - rsst3*r31(jdr)/(d31**3*d12)
    1278              :             END IF
    1279      5465196 :             IF (ABS(denom1) <= 0.011_dp) D_mat(1, 1) = 0.0_dp
    1280      5465196 :             IF (ABS(denom2) <= 0.011_dp) D_mat(2, 1) = 0.0_dp
    1281      5465196 :             IF (ABS(denom3) <= 0.011_dp) D_mat(3, 1) = 0.0_dp
    1282              : 
    1283              :             deriv = deriv + ka1*D_mat(1, 1)*D_mat(1, 2)/denom1 + &
    1284              :                     ka2*D_mat(2, 1)*D_mat(2, 2)/denom2 + &
    1285      6115032 :                     ka3*D_mat(3, 1)*D_mat(3, 2)/denom3
    1286              :          END DO
    1287              :       END IF
    1288       245871 :       deriv = 0.25_dp*deriv
    1289              : 
    1290       245871 :    END FUNCTION angle_second_deriv
    1291              : 
    1292              : END MODULE bfgs_optimizer
        

Generated by: LCOV version 2.0-1