LCOV - code coverage report
Current view: top level - src - qs_ot_minimizer.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:9e7f125) Lines: 685 800 85.6 %
Date: 2025-05-16 07:28:05 Functions: 15 15 100.0 %

          Line data    Source code
       1             : !--------------------------------------------------------------------------------------------------!
       2             : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3             : !   Copyright 2000-2025 CP2K developers group <https://cp2k.org>                                   !
       4             : !                                                                                                  !
       5             : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6             : !--------------------------------------------------------------------------------------------------!
       7             : 
       8             : ! **************************************************************************************************
       9             : !> \brief orbital transformations
      10             : !> \par History
      11             : !>      None
      12             : !> \author Joost VandeVondele (09.2002)
      13             : ! **************************************************************************************************
      14             : MODULE qs_ot_minimizer
      15             : 
      16             :    USE cp_dbcsr_api,                    ONLY: dbcsr_add,&
      17             :                                               dbcsr_copy,&
      18             :                                               dbcsr_get_info,&
      19             :                                               dbcsr_p_type,&
      20             :                                               dbcsr_scale,&
      21             :                                               dbcsr_set
      22             :    USE cp_dbcsr_contrib,                ONLY: dbcsr_dot,&
      23             :                                               dbcsr_init_random
      24             :    USE cp_log_handling,                 ONLY: cp_get_default_logger,&
      25             :                                               cp_logger_get_default_unit_nr,&
      26             :                                               cp_logger_type
      27             :    USE kinds,                           ONLY: dp,&
      28             :                                               int_8
      29             :    USE mathlib,                         ONLY: diamat_all
      30             :    USE preconditioner,                  ONLY: apply_preconditioner
      31             :    USE qs_ot,                           ONLY: qs_ot_get_derivative,&
      32             :                                               qs_ot_get_derivative_ref
      33             :    USE qs_ot_types,                     ONLY: qs_ot_type
      34             : #include "./base/base_uses.f90"
      35             : 
      36             :    IMPLICIT NONE
      37             : 
      38             :    PRIVATE
      39             : 
      40             :    PUBLIC  :: ot_mini
      41             : 
      42             :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_ot_minimizer'
      43             : 
      44             : CONTAINS
      45             : !
      46             : ! the minimizer interface
      47             : ! should present all possible modes of minimization
      48             : ! these include CG SD DIIS
      49             : !
      50             : !
      51             : ! IN the case of nspin != 1 we have a gradient that is distributed over different qs_ot_env.
      52             : ! still things remain basically the same, since there are no constraints between the different qs_ot_env
      53             : ! we only should take care that the various scalar products are taken over the full vectors.
      54             : ! all the information needed and collected can be stored in the fist qs_ot_env only
      55             : ! (indicating that the data type for the gradient/position and minization should be separated)
      56             : !
      57             : ! **************************************************************************************************
      58             : !> \brief ...
      59             : !> \param qs_ot_env ...
      60             : !> \param matrix_hc ...
      61             : ! **************************************************************************************************
      62       81292 :    SUBROUTINE ot_mini(qs_ot_env, matrix_hc)
      63             :       TYPE(qs_ot_type), DIMENSION(:), POINTER            :: qs_ot_env
      64             :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_hc
      65             : 
      66             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'ot_mini'
      67             : 
      68             :       INTEGER                                            :: handle, ispin, nspin
      69             :       LOGICAL                                            :: do_ener, do_ks
      70             :       REAL(KIND=dp)                                      :: tmp
      71             : 
      72       81292 :       CALL timeset(routineN, handle)
      73             : 
      74       81292 :       nspin = SIZE(qs_ot_env)
      75             : 
      76       81292 :       do_ks = qs_ot_env(1)%settings%ks
      77       81292 :       do_ener = qs_ot_env(1)%settings%do_ener
      78             : 
      79       81292 :       qs_ot_env(1)%OT_METHOD_FULL = ""
      80             : 
      81             :       ! compute the gradient for the variables x
      82       81292 :       IF (.NOT. qs_ot_env(1)%energy_only) THEN
      83       61788 :          qs_ot_env(1)%gradient = 0.0_dp
      84      131071 :          DO ispin = 1, nspin
      85       69283 :             IF (do_ks) THEN
      86      135570 :                SELECT CASE (qs_ot_env(1)%settings%ot_algorithm)
      87             :                CASE ("TOD")
      88             :                   CALL qs_ot_get_derivative(matrix_hc(ispin)%matrix, qs_ot_env(ispin)%matrix_x, &
      89             :                                             qs_ot_env(ispin)%matrix_sx, &
      90       66287 :                                             qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin))
      91             :                CASE ("REF")
      92             :                   CALL qs_ot_get_derivative_ref(matrix_hc(ispin)%matrix, &
      93             :                                                 qs_ot_env(ispin)%matrix_x, qs_ot_env(ispin)%matrix_sx, &
      94        2996 :                                                 qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin))
      95             :                CASE DEFAULT
      96       69283 :                   CPABORT("ALGORITHM NYI")
      97             :                END SELECT
      98             :             END IF
      99             :             ! and also the gradient along the direction
     100      131071 :             IF (qs_ot_env(1)%use_dx) THEN
     101       64539 :                IF (do_ks) THEN
     102       64539 :                   CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_dx, tmp)
     103       64539 :                   qs_ot_env(1)%gradient = qs_ot_env(1)%gradient + tmp
     104       64539 :                   IF (qs_ot_env(1)%settings%do_rotation) THEN
     105        1630 :                      CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx, qs_ot_env(ispin)%rot_mat_dx, tmp)
     106        1630 :                      qs_ot_env(1)%gradient = qs_ot_env(1)%gradient + 0.5_dp*tmp
     107             :                   END IF
     108             :                END IF
     109       64539 :                IF (do_ener) THEN
     110           0 :                   tmp = DOT_PRODUCT(qs_ot_env(ispin)%ener_gx, qs_ot_env(ispin)%ener_dx)
     111           0 :                   qs_ot_env(1)%gradient = qs_ot_env(1)%gradient + tmp
     112             :                END IF
     113             :             ELSE
     114        4744 :                IF (do_ks) THEN
     115        4744 :                   CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_gx, tmp)
     116        4744 :                   qs_ot_env(1)%gradient = qs_ot_env(1)%gradient - tmp
     117        4744 :                   IF (qs_ot_env(1)%settings%do_rotation) THEN
     118           0 :                      CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx, qs_ot_env(ispin)%rot_mat_gx, tmp)
     119           0 :                      qs_ot_env(1)%gradient = qs_ot_env(1)%gradient - 0.5_dp*tmp
     120             :                   END IF
     121             :                END IF
     122        4744 :                IF (do_ener) THEN
     123           0 :                   tmp = DOT_PRODUCT(qs_ot_env(ispin)%ener_gx, qs_ot_env(ispin)%ener_gx)
     124           0 :                   qs_ot_env(1)%gradient = qs_ot_env(1)%gradient - tmp
     125             :                END IF
     126             :             END IF
     127             :          END DO
     128             :       END IF
     129             : 
     130      121804 :       SELECT CASE (qs_ot_env(1)%settings%OT_METHOD)
     131             :       CASE ("CG")
     132       40512 :          IF (current_point_is_fine(qs_ot_env)) THEN
     133       21102 :             qs_ot_env(1)%OT_METHOD_FULL = "OT CG"
     134       21102 :             CALL ot_new_cg_direction(qs_ot_env)
     135       21102 :             qs_ot_env(1)%line_search_count = 0
     136             :          ELSE
     137       19410 :             qs_ot_env(1)%OT_METHOD_FULL = "OT LS"
     138             :          END IF
     139       40512 :          CALL do_line_search(qs_ot_env)
     140             :       CASE ("SD")
     141         132 :          IF (current_point_is_fine(qs_ot_env)) THEN
     142          38 :             qs_ot_env(1)%OT_METHOD_FULL = "OT SD"
     143          38 :             CALL ot_new_sd_direction(qs_ot_env)
     144          38 :             qs_ot_env(1)%line_search_count = 0
     145             :          ELSE
     146          94 :             qs_ot_env(1)%OT_METHOD_FULL = "OT LS"
     147             :          END IF
     148         132 :          CALL do_line_search(qs_ot_env)
     149             :       CASE ("DIIS")
     150       40472 :          qs_ot_env(1)%OT_METHOD_FULL = "OT DIIS"
     151       40472 :          CALL ot_diis_step(qs_ot_env)
     152             :       CASE ("BROY")
     153         176 :          qs_ot_env(1)%OT_METHOD_FULL = "OT BROY"
     154         176 :          CALL ot_broyden_step(qs_ot_env)
     155             :       CASE DEFAULT
     156       81292 :          CPABORT("OT_METHOD NYI")
     157             :       END SELECT
     158             : 
     159       81292 :       CALL timestop(handle)
     160             : 
     161       81292 :    END SUBROUTINE ot_mini
     162             : 
     163             : !
     164             : ! checks if the current point is a good point for finding a new direction
     165             : ! or if we should improve the line_search, if it is used
     166             : !
     167             : ! **************************************************************************************************
     168             : !> \brief ...
     169             : !> \param qs_ot_env ...
     170             : !> \return ...
     171             : ! **************************************************************************************************
     172       40644 :    FUNCTION current_point_is_fine(qs_ot_env) RESULT(res)
     173             :       TYPE(qs_ot_type), DIMENSION(:), POINTER            :: qs_ot_env
     174             :       LOGICAL                                            :: res
     175             : 
     176       40644 :       res = .FALSE.
     177             : 
     178             :       ! only if we have a gradient it can be fine
     179       40644 :       IF (.NOT. qs_ot_env(1)%energy_only) THEN
     180             : 
     181             :          ! we have not yet started with the line search
     182       21140 :          IF (qs_ot_env(1)%line_search_count .EQ. 0) THEN
     183       40644 :             res = .TRUE.
     184             :             RETURN
     185             :          END IF
     186             : 
     187       18292 :          IF (qs_ot_env(1)%line_search_might_be_done) THEN
     188             :             ! here we put the more complicated logic later
     189       18292 :             res = .TRUE.
     190       18292 :             RETURN
     191             :          END IF
     192             : 
     193             :       END IF
     194             : 
     195             :    END FUNCTION current_point_is_fine
     196             : 
     197             : !
     198             : ! performs various kinds of line searches
     199             : !
     200             : ! **************************************************************************************************
     201             : !> \brief ...
     202             : !> \param qs_ot_env ...
     203             : ! **************************************************************************************************
     204       40644 :    SUBROUTINE do_line_search(qs_ot_env)
     205             :       TYPE(qs_ot_type), DIMENSION(:), POINTER            :: qs_ot_env
     206             : 
     207       41072 :       SELECT CASE (qs_ot_env(1)%settings%line_search_method)
     208             :       CASE ("GOLD")
     209         428 :          CALL do_line_search_gold(qs_ot_env)
     210             :       CASE ("3PNT")
     211        1724 :          CALL do_line_search_3pnt(qs_ot_env)
     212             :       CASE ("2PNT")
     213       38252 :          CALL do_line_search_2pnt(qs_ot_env)
     214             :       CASE ("ADPT")
     215         230 :          CALL do_line_search_adapt(qs_ot_env)
     216             :       CASE ("NONE")
     217          10 :          CALL do_line_search_none(qs_ot_env)
     218             :       CASE DEFAULT
     219       40644 :          CPABORT("NYI")
     220             :       END SELECT
     221       40644 :    END SUBROUTINE do_line_search
     222             : 
     223             : ! **************************************************************************************************
     224             : !> \brief moves x adding the right amount (ds) of the gradient or search direction
     225             : !> \param ds ...
     226             : !> \param qs_ot_env ...
     227             : !> \par History
     228             : !>      08.2004 created [ Joost VandeVondele ] copied here from a larger number of subroutines
     229             : ! **************************************************************************************************
     230       40644 :    SUBROUTINE take_step(ds, qs_ot_env)
     231             :       REAL(KIND=dp)                                      :: ds
     232             :       TYPE(qs_ot_type), DIMENSION(:), POINTER            :: qs_ot_env
     233             : 
     234             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'take_step'
     235             : 
     236             :       INTEGER                                            :: handle, ispin, nspin
     237             :       LOGICAL                                            :: do_ener, do_ks
     238             : 
     239       40644 :       CALL timeset(routineN, handle)
     240             : 
     241       40644 :       nspin = SIZE(qs_ot_env)
     242             : 
     243       40644 :       do_ks = qs_ot_env(1)%settings%ks
     244       40644 :       do_ener = qs_ot_env(1)%settings%do_ener
     245             : 
     246             :       ! now update x to take into account this new step
     247             :       ! either dx or -gx is the direction to use
     248       40644 :       IF (qs_ot_env(1)%use_dx) THEN
     249       40556 :          IF (do_ks) THEN
     250       89315 :             DO ispin = 1, nspin
     251             :                CALL dbcsr_add(qs_ot_env(ispin)%matrix_x, qs_ot_env(ispin)%matrix_dx, &
     252       48759 :                               alpha_scalar=1.0_dp, beta_scalar=ds)
     253       89315 :                IF (qs_ot_env(ispin)%settings%do_rotation) THEN
     254             :                   CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_x, qs_ot_env(ispin)%rot_mat_dx, &
     255        2644 :                                  alpha_scalar=1.0_dp, beta_scalar=ds)
     256             :                END IF
     257             :             END DO
     258             :          END IF
     259       40556 :          IF (do_ener) THEN
     260           0 :             DO ispin = 1, nspin
     261           0 :                qs_ot_env(ispin)%ener_x = qs_ot_env(ispin)%ener_x + ds*qs_ot_env(ispin)%ener_dx
     262             :             END DO
     263             :          END IF
     264             :       ELSE
     265          88 :          IF (do_ks) THEN
     266         176 :             DO ispin = 1, nspin
     267             :                CALL dbcsr_add(qs_ot_env(ispin)%matrix_x, qs_ot_env(ispin)%matrix_gx, &
     268          88 :                               alpha_scalar=1.0_dp, beta_scalar=-ds)
     269         176 :                IF (qs_ot_env(ispin)%settings%do_rotation) THEN
     270             :                   CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_x, qs_ot_env(ispin)%rot_mat_gx, &
     271           0 :                                  alpha_scalar=1.0_dp, beta_scalar=-ds)
     272             :                END IF
     273             :             END DO
     274             :          END IF
     275          88 :          IF (do_ener) THEN
     276           0 :             DO ispin = 1, nspin
     277           0 :                qs_ot_env(ispin)%ener_x = qs_ot_env(ispin)%ener_x - ds*qs_ot_env(ispin)%ener_gx
     278             :             END DO
     279             :          END IF
     280             :       END IF
     281       40644 :       CALL timestop(handle)
     282       40644 :    END SUBROUTINE take_step
     283             : 
     284             : ! implements a golden ratio search as a robust way of minimizing
     285             : ! **************************************************************************************************
     286             : !> \brief ...
     287             : !> \param qs_ot_env ...
     288             : ! **************************************************************************************************
     289         428 :    SUBROUTINE do_line_search_gold(qs_ot_env)
     290             : 
     291             :       TYPE(qs_ot_type), DIMENSION(:), POINTER            :: qs_ot_env
     292             : 
     293             :       CHARACTER(len=*), PARAMETER :: routineN = 'do_line_search_gold'
     294             :       REAL(KIND=dp), PARAMETER                           :: gold_sec = 0.3819_dp
     295             : 
     296             :       INTEGER                                            :: count, handle
     297             :       REAL(KIND=dp)                                      :: ds
     298             : 
     299         428 :       CALL timeset(routineN, handle)
     300             : 
     301         428 :       qs_ot_env(1)%line_search_count = qs_ot_env(1)%line_search_count + 1
     302         428 :       count = qs_ot_env(1)%line_search_count
     303         428 :       qs_ot_env(1)%line_search_might_be_done = .FALSE.
     304         428 :       qs_ot_env(1)%energy_only = .TRUE.
     305             : 
     306         428 :       IF (count + 1 .GT. SIZE(qs_ot_env(1)%OT_pos)) THEN
     307             :          ! should not happen, we pass with a warning first
     308             :          ! you can increase the size of OT_pos and the like in qs_ot_env
     309           0 :          CPABORT("MAX ITER EXCEEDED : FATAL")
     310             :       END IF
     311             : 
     312         428 :       IF (qs_ot_env(1)%line_search_count .EQ. 1) THEN
     313          54 :          qs_ot_env(1)%line_search_left = 1
     314          54 :          qs_ot_env(1)%line_search_right = 0
     315          54 :          qs_ot_env(1)%line_search_mid = 1
     316          54 :          qs_ot_env(1)%ot_pos(1) = 0.0_dp
     317          54 :          qs_ot_env(1)%ot_energy(1) = qs_ot_env(1)%etotal
     318          54 :          qs_ot_env(1)%ot_pos(2) = qs_ot_env(1)%ds_min/gold_sec
     319             :       ELSE
     320         374 :          qs_ot_env(1)%ot_energy(count) = qs_ot_env(1)%etotal
     321             :          ! it's essentially a book keeping game.
     322             :          ! keep left on the left, keep (bring) right on the right
     323             :          ! and mid in between these two
     324         374 :          IF (qs_ot_env(1)%line_search_right .EQ. 0) THEN ! we do not yet have the right bracket
     325          64 :             IF (qs_ot_env(1)%ot_energy(count - 1) .LT. qs_ot_env(1)%ot_energy(count)) THEN
     326          42 :                qs_ot_env(1)%line_search_right = count
     327             :                qs_ot_env(1)%ot_pos(count + 1) = qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_mid) + &
     328             :                                                 (qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_right) - &
     329          42 :                                                  qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_mid))*gold_sec
     330             :             ELSE
     331          22 :                qs_ot_env(1)%line_search_left = qs_ot_env(1)%line_search_mid
     332          22 :                qs_ot_env(1)%line_search_mid = count
     333          22 :                qs_ot_env(1)%ot_pos(count + 1) = qs_ot_env(1)%ot_pos(count)/gold_sec ! expand
     334             :             END IF
     335             :          ELSE
     336             :             ! first determine where we are and construct the new triplet
     337         310 :             IF (qs_ot_env(1)%ot_pos(count) .LT. qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_mid)) THEN
     338         126 :                IF (qs_ot_env(1)%ot_energy(count) .LT. qs_ot_env(1)%ot_energy(qs_ot_env(1)%line_search_mid)) THEN
     339          42 :                   qs_ot_env(1)%line_search_right = qs_ot_env(1)%line_search_mid
     340          42 :                   qs_ot_env(1)%line_search_mid = count
     341             :                ELSE
     342          84 :                   qs_ot_env(1)%line_search_left = count
     343             :                END IF
     344             :             ELSE
     345         184 :                IF (qs_ot_env(1)%ot_energy(count) .LT. qs_ot_env(1)%ot_energy(qs_ot_env(1)%line_search_mid)) THEN
     346          76 :                   qs_ot_env(1)%line_search_left = qs_ot_env(1)%line_search_mid
     347          76 :                   qs_ot_env(1)%line_search_mid = count
     348             :                ELSE
     349         108 :                   qs_ot_env(1)%line_search_right = count
     350             :                END IF
     351             :             END IF
     352             :             ! now find the new point in the largest section
     353         310 :             IF ((qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_right) &
     354             :                  - qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_mid)) .GT. &
     355             :                 (qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_mid) &
     356             :                  - qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_left))) THEN
     357             :                qs_ot_env(1)%ot_pos(count + 1) = &
     358             :                   qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_mid) + &
     359             :                   gold_sec*(qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_right) &
     360         162 :                             - qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_mid))
     361             :             ELSE
     362             :                qs_ot_env(1)%ot_pos(count + 1) = &
     363             :                   qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_left) + &
     364             :                   gold_sec*(qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_mid) &
     365         148 :                             - qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_left))
     366             :             END IF
     367             :             ! check for termination
     368             :             IF (((qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_right) &
     369             :                   - qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_mid)) .LT. &
     370         310 :                  qs_ot_env(1)%ds_min*qs_ot_env(1)%settings%gold_target) .AND. &
     371             :                 ((qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_mid) &
     372             :                   - qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_left)) .LT. &
     373             :                  qs_ot_env(1)%ds_min*qs_ot_env(1)%settings%gold_target)) THEN
     374          42 :                qs_ot_env(1)%energy_only = .FALSE.
     375          42 :                qs_ot_env(1)%line_search_might_be_done = .TRUE.
     376             :             END IF
     377             :          END IF
     378             :       END IF
     379         428 :       ds = qs_ot_env(1)%OT_pos(count + 1) - qs_ot_env(1)%OT_pos(count)
     380         428 :       qs_ot_env(1)%ds_min = qs_ot_env(1)%OT_pos(count + 1)
     381             : 
     382         428 :       CALL take_step(ds, qs_ot_env)
     383             : 
     384         428 :       CALL timestop(handle)
     385             : 
     386         428 :    END SUBROUTINE do_line_search_gold
     387             : 
     388             : ! **************************************************************************************************
     389             : !> \brief ...
     390             : !> \param qs_ot_env ...
     391             : ! **************************************************************************************************
     392        1724 :    SUBROUTINE do_line_search_3pnt(qs_ot_env)
     393             : 
     394             :       TYPE(qs_ot_type), DIMENSION(:), POINTER            :: qs_ot_env
     395             : 
     396             :       CHARACTER(len=*), PARAMETER :: routineN = 'do_line_search_3pnt'
     397             : 
     398             :       INTEGER                                            :: count, handle
     399             :       REAL(KIND=dp)                                      :: denom, ds, fa, fb, fc, nom, pos, val, &
     400             :                                                             xa, xb, xc
     401             : 
     402        1724 :       CALL timeset(routineN, handle)
     403             : 
     404        1724 :       qs_ot_env(1)%line_search_might_be_done = .FALSE.
     405        1724 :       qs_ot_env(1)%energy_only = .TRUE.
     406             : 
     407             :       ! a three point interpolation based on the energy
     408        1724 :       qs_ot_env(1)%line_search_count = qs_ot_env(1)%line_search_count + 1
     409        1724 :       count = qs_ot_env(1)%line_search_count
     410        1724 :       qs_ot_env(1)%ot_energy(count) = qs_ot_env(1)%etotal
     411         600 :       SELECT CASE (count)
     412             :       CASE (1)
     413         600 :          qs_ot_env(1)%ot_pos(count) = 0.0_dp
     414         600 :          qs_ot_env(1)%ot_pos(count + 1) = qs_ot_env(1)%ds_min*0.8_dp
     415             :       CASE (2)
     416         562 :          IF (qs_ot_env(1)%OT_energy(count) .GT. qs_ot_env(1)%OT_energy(count - 1)) THEN
     417          66 :             qs_ot_env(1)%OT_pos(count + 1) = qs_ot_env(1)%ds_min*0.5_dp
     418             :          ELSE
     419         496 :             qs_ot_env(1)%OT_pos(count + 1) = qs_ot_env(1)%ds_min*1.4_dp
     420             :          END IF
     421             :       CASE (3)
     422         562 :          xa = qs_ot_env(1)%OT_pos(1)
     423         562 :          xb = qs_ot_env(1)%OT_pos(2)
     424         562 :          xc = qs_ot_env(1)%OT_pos(3)
     425         562 :          fa = qs_ot_env(1)%OT_energy(1)
     426         562 :          fb = qs_ot_env(1)%OT_energy(2)
     427         562 :          fc = qs_ot_env(1)%OT_energy(3)
     428         562 :          nom = (xb - xa)**2*(fb - fc) - (xb - xc)**2*(fb - fa)
     429         562 :          denom = (xb - xa)*(fb - fc) - (xb - xc)*(fb - fa)
     430         562 :          IF (ABS(denom) .LE. 1.0E-18_dp*MAX(ABS(fb - fc), ABS(fb - fa))) THEN
     431             :             pos = xb
     432             :          ELSE
     433         562 :             pos = xb - 0.5_dp*nom/denom ! position of the stationary point
     434             :          END IF
     435             :          val = (pos - xa)*(pos - xb)*fc/((xc - xa)*(xc - xb)) + &
     436             :                (pos - xb)*(pos - xc)*fa/((xa - xb)*(xa - xc)) + &
     437         562 :                (pos - xc)*(pos - xa)*fb/((xb - xc)*(xb - xa))
     438         562 :          IF (val .LT. fa .AND. val .LE. fb .AND. val .LE. fc) THEN ! OK, we go to a minimum
     439             :             ! we take a guard against too large steps
     440             :             qs_ot_env(1)%OT_pos(count + 1) = MAX(MAXVAL(qs_ot_env(1)%OT_pos(1:3))*0.01_dp, &
     441        2790 :                                                  MIN(pos, MAXVAL(qs_ot_env(1)%OT_pos(1:3))*4.0_dp))
     442             :          ELSE ! just take an extended step
     443          20 :             qs_ot_env(1)%OT_pos(count + 1) = MAXVAL(qs_ot_env(1)%OT_pos(1:3))*2.0_dp
     444             :          END IF
     445         562 :          qs_ot_env(1)%energy_only = .FALSE.
     446         562 :          qs_ot_env(1)%line_search_might_be_done = .TRUE.
     447             :       CASE DEFAULT
     448        1724 :          CPABORT("NYI")
     449             :       END SELECT
     450        1724 :       ds = qs_ot_env(1)%OT_pos(count + 1) - qs_ot_env(1)%OT_pos(count)
     451        1724 :       qs_ot_env(1)%ds_min = qs_ot_env(1)%OT_pos(count + 1)
     452             : 
     453        1724 :       CALL take_step(ds, qs_ot_env)
     454             : 
     455        1724 :       CALL timestop(handle)
     456             : 
     457        1724 :    END SUBROUTINE do_line_search_3pnt
     458             : 
     459             : ! **************************************************************************************************
     460             : !> \brief ...
     461             : !> \param qs_ot_env ...
     462             : ! **************************************************************************************************
     463       38252 :    SUBROUTINE do_line_search_2pnt(qs_ot_env)
     464             : 
     465             :       TYPE(qs_ot_type), DIMENSION(:), POINTER            :: qs_ot_env
     466             : 
     467             :       CHARACTER(len=*), PARAMETER :: routineN = 'do_line_search_2pnt'
     468             : 
     469             :       INTEGER                                            :: count, handle
     470             :       REAL(KIND=dp)                                      :: a, b, c, ds, pos, val, x0, x1
     471             : 
     472       38252 :       CALL timeset(routineN, handle)
     473             : 
     474       38252 :       qs_ot_env(1)%line_search_might_be_done = .FALSE.
     475       38252 :       qs_ot_env(1)%energy_only = .TRUE.
     476             : 
     477             :       ! a three point interpolation based on the energy
     478       38252 :       qs_ot_env(1)%line_search_count = qs_ot_env(1)%line_search_count + 1
     479       38252 :       count = qs_ot_env(1)%line_search_count
     480       38252 :       qs_ot_env(1)%ot_energy(count) = qs_ot_env(1)%etotal
     481       20408 :       SELECT CASE (count)
     482             :       CASE (1)
     483       20408 :          qs_ot_env(1)%ot_pos(count) = 0.0_dp
     484       20408 :          qs_ot_env(1)%ot_grad(count) = qs_ot_env(1)%gradient
     485       20408 :          qs_ot_env(1)%ot_pos(count + 1) = qs_ot_env(1)%ds_min*1.0_dp
     486             :       CASE (2)
     487       17844 :          x0 = 0.0_dp
     488       17844 :          c = qs_ot_env(1)%ot_energy(1)
     489       17844 :          b = qs_ot_env(1)%ot_grad(1)
     490       17844 :          x1 = qs_ot_env(1)%ot_pos(2)
     491       17844 :          a = (qs_ot_env(1)%ot_energy(2) - b*x1 - c)/(x1**2)
     492       17844 :          IF (a .LE. 0.0_dp) a = 1.0E-15_dp
     493       17844 :          pos = -b/(2.0_dp*a)
     494       17844 :          val = a*pos**2 + b*pos + c
     495       17844 :          qs_ot_env(1)%energy_only = .FALSE.
     496       17844 :          qs_ot_env(1)%line_search_might_be_done = .TRUE.
     497       17844 :          IF (val .LT. qs_ot_env(1)%ot_energy(1) .AND. val .LE. qs_ot_env(1)%ot_energy(2)) THEN
     498             :             ! we go to a minimum, but ...
     499             :             ! we take a guard against too large steps
     500             :             qs_ot_env(1)%OT_pos(count + 1) = MAX(MAXVAL(qs_ot_env(1)%OT_pos(1:2))*0.01_dp, &
     501       71160 :                                                  MIN(pos, MAXVAL(qs_ot_env(1)%OT_pos(1:2))*4.0_dp))
     502             :          ELSE ! just take an extended step
     503         216 :             qs_ot_env(1)%OT_pos(count + 1) = MAXVAL(qs_ot_env(1)%OT_pos(1:2))*2.0_dp
     504             :          END IF
     505             :       CASE DEFAULT
     506       38252 :          CPABORT("NYI")
     507             :       END SELECT
     508       38252 :       ds = qs_ot_env(1)%OT_pos(count + 1) - qs_ot_env(1)%OT_pos(count)
     509       38252 :       qs_ot_env(1)%ds_min = qs_ot_env(1)%OT_pos(count + 1)
     510             : 
     511       38252 :       CALL take_step(ds, qs_ot_env)
     512             : 
     513       38252 :       CALL timestop(handle)
     514             : 
     515       38252 :    END SUBROUTINE do_line_search_2pnt
     516             : 
     517             : ! **************************************************************************************************
     518             : !> \brief ...
     519             : !> \param qs_ot_env ...
     520             : ! **************************************************************************************************
     521         230 :    SUBROUTINE do_line_search_adapt(qs_ot_env)
     522             : 
     523             :       TYPE(qs_ot_type), DIMENSION(:), POINTER            :: qs_ot_env
     524             : 
     525             :       CHARACTER(len=*), PARAMETER :: routineN = 'do_line_search_adapt'
     526             :       REAL(KIND=dp), PARAMETER                           :: grow_factor = 2.0_dp, &
     527             :                                                             shrink_factor = 0.5_dp
     528             : 
     529             :       INTEGER                                            :: count, handle, il, im, ir
     530             :       REAL(KIND=dp)                                      :: a, b, c, denom, ds, el, em, er, &
     531             :                                                             step_size, xl, xm, xr
     532             : 
     533         230 :       CALL timeset(routineN, handle)
     534             : 
     535         230 :       qs_ot_env(1)%line_search_count = qs_ot_env(1)%line_search_count + 1
     536         230 :       count = qs_ot_env(1)%line_search_count
     537         230 :       qs_ot_env(1)%line_search_might_be_done = .FALSE.
     538         230 :       qs_ot_env(1)%energy_only = .TRUE.
     539             : 
     540         230 :       IF (count + 1 > SIZE(qs_ot_env(1)%OT_pos)) THEN
     541             :          ! should not happen, we pass with a warning first
     542             :          ! you can increase the size of OT_pos and the like in qs_ot_env
     543           0 :          CPABORT("MAX ITER EXCEEDED : FATAL")
     544             :       END IF
     545             : 
     546             :       ! Perform an adaptive linesearch
     547         230 :       IF (qs_ot_env(1)%line_search_count == 1) THEN
     548          68 :          qs_ot_env(1)%line_search_left = 1
     549          68 :          qs_ot_env(1)%line_search_right = 0
     550          68 :          qs_ot_env(1)%line_search_mid = 1
     551          68 :          qs_ot_env(1)%ot_Pos(1) = 0.0_dp
     552          68 :          qs_ot_env(1)%ot_energy(1) = qs_ot_env(1)%etotal
     553          68 :          qs_ot_env(1)%ot_Pos(2) = qs_ot_env(1)%ds_min*grow_factor
     554             :       ELSE
     555         162 :          qs_ot_env(1)%ot_energy(count) = qs_ot_env(1)%etotal
     556             :          ! it's essentially a book keeping game.
     557             :          ! keep left on the left, keep (bring) right on the right
     558             :          ! and mid in between these two
     559         162 :          IF (qs_ot_env(1)%line_search_right == 0) THEN ! we do not yet have the right bracket
     560          88 :             IF (qs_ot_env(1)%ot_energy(count - 1) < qs_ot_env(1)%ot_energy(count)) THEN
     561          58 :                qs_ot_env(1)%line_search_right = count
     562             :                qs_ot_env(1)%ot_Pos(count + 1) = qs_ot_env(1)%ot_Pos(qs_ot_env(1)%line_search_mid) + &
     563             :                                                 (qs_ot_env(1)%ot_Pos(qs_ot_env(1)%line_search_right) - &
     564          58 :                                                  qs_ot_env(1)%ot_Pos(qs_ot_env(1)%line_search_mid))*shrink_factor
     565             :             ELSE
     566             :                ! expand further
     567          30 :                qs_ot_env(1)%line_search_left = qs_ot_env(1)%line_search_mid
     568          30 :                qs_ot_env(1)%line_search_mid = count
     569          30 :                qs_ot_env(1)%ot_Pos(count + 1) = qs_ot_env(1)%ot_Pos(count)*grow_factor
     570             :             END IF
     571             :          ELSE
     572             :             ! first determine where we are and construct the new triplet
     573          74 :             IF (qs_ot_env(1)%ot_pos(count) < qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_mid)) THEN
     574           0 :                IF (qs_ot_env(1)%ot_energy(count) < qs_ot_env(1)%ot_energy(qs_ot_env(1)%line_search_mid)) THEN
     575           0 :                   qs_ot_env(1)%line_search_right = qs_ot_env(1)%line_search_mid
     576           0 :                   qs_ot_env(1)%line_search_mid = count
     577             :                ELSE
     578           0 :                   qs_ot_env(1)%line_search_left = count
     579             :                END IF
     580             :             ELSE
     581          74 :                IF (qs_ot_env(1)%ot_energy(count) < qs_ot_env(1)%ot_energy(qs_ot_env(1)%line_search_mid)) THEN
     582          36 :                   qs_ot_env(1)%line_search_left = qs_ot_env(1)%line_search_mid
     583          36 :                   qs_ot_env(1)%line_search_mid = count
     584             :                ELSE
     585          38 :                   qs_ot_env(1)%line_search_right = count
     586             :                END IF
     587             :             END IF
     588          74 :             il = qs_ot_env(1)%line_search_left
     589          74 :             im = qs_ot_env(1)%line_search_mid
     590          74 :             ir = qs_ot_env(1)%line_search_right
     591          74 :             xl = qs_ot_env(1)%OT_pos(il)
     592          74 :             xm = qs_ot_env(1)%OT_pos(im)
     593          74 :             xr = qs_ot_env(1)%OT_pos(ir)
     594          74 :             el = qs_ot_env(1)%ot_energy(il)
     595          74 :             em = qs_ot_env(1)%ot_energy(im)
     596          74 :             er = qs_ot_env(1)%ot_energy(ir)
     597          74 :             IF (em < el) THEN
     598          58 :                IF (er < em) THEN
     599             :                   !extend search
     600           0 :                   qs_ot_env(1)%ot_Pos(count + 1) = qs_ot_env(1)%ot_Pos(ir)*grow_factor
     601             :                ELSE
     602             :                   ! Cramer's rule
     603          58 :                   denom = (xl - xm)*(xl - xr)*(xm - xr)
     604          58 :                   a = (xr*(em - el) + xm*(el - er) + xl*(er - em))/denom
     605          58 :                   b = (xr**2*(el - em) + xm**2*(er - el) + xl**2*(em - er))/denom
     606          58 :                   c = (xm*xr*(xm - xr)*el + xr*xl*(xr - xl)*em + xr*xm*(xr - xm)*er)/denom
     607             : 
     608          58 :                   IF (ABS(a) /= 0.0_dp) THEN
     609          58 :                      step_size = -b/(2.0_dp*a)
     610             :                   ELSE
     611             :                      step_size = 0.0_dp
     612             :                   END IF
     613          58 :                   CPASSERT(step_size >= 0.0_dp)
     614          58 :                   qs_ot_env(1)%ot_Pos(count + 1) = step_size
     615          58 :                   qs_ot_env(1)%line_search_might_be_done = .TRUE.
     616          58 :                   qs_ot_env(1)%energy_only = .FALSE.
     617             :                END IF
     618             :             ELSE
     619             :                ! contract search
     620             :                qs_ot_env(1)%ot_Pos(count + 1) = qs_ot_env(1)%ot_Pos(im) + &
     621          16 :                                                 (qs_ot_env(1)%ot_Pos(ir) - qs_ot_env(1)%ot_Pos(im))*shrink_factor
     622             :             END IF
     623             : 
     624             :          END IF
     625             :       END IF
     626         230 :       ds = qs_ot_env(1)%OT_pos(count + 1) - qs_ot_env(1)%OT_pos(count)
     627         230 :       qs_ot_env(1)%ds_min = qs_ot_env(1)%OT_pos(count + 1)
     628             : 
     629         230 :       CALL take_step(ds, qs_ot_env)
     630             : 
     631         230 :       CALL timestop(handle)
     632             : 
     633         230 :    END SUBROUTINE do_line_search_adapt
     634             : 
     635             : ! **************************************************************************************************
     636             : !> \brief ...
     637             : !> \param qs_ot_env ...
     638             : ! **************************************************************************************************
     639          10 :    SUBROUTINE do_line_search_none(qs_ot_env)
     640             :       TYPE(qs_ot_type), DIMENSION(:), POINTER            :: qs_ot_env
     641             : 
     642          10 :       CALL take_step(qs_ot_env(1)%ds_min, qs_ot_env)
     643             : 
     644          10 :    END SUBROUTINE do_line_search_none
     645             : 
     646             : !
     647             : ! creates a new SD direction, using the preconditioner if associated
     648             : ! also updates the gradient for line search
     649             : !
     650             : 
     651             : ! **************************************************************************************************
     652             : !> \brief ...
     653             : !> \param qs_ot_env ...
     654             : ! **************************************************************************************************
     655          38 :    SUBROUTINE ot_new_sd_direction(qs_ot_env)
     656             :       TYPE(qs_ot_type), DIMENSION(:), POINTER            :: qs_ot_env
     657             : 
     658             :       CHARACTER(len=*), PARAMETER :: routineN = 'ot_new_sd_direction'
     659             : 
     660             :       INTEGER                                            :: handle, ispin, itmp, k, n, nener, nspin
     661             :       LOGICAL                                            :: do_ener, do_ks
     662             :       REAL(KIND=dp)                                      :: tmp
     663             :       TYPE(cp_logger_type), POINTER                      :: logger
     664             : 
     665          38 :       CALL timeset(routineN, handle)
     666             : 
     667             : !***SCP
     668             : 
     669          38 :       nspin = SIZE(qs_ot_env)
     670          38 :       logger => cp_get_default_logger()
     671          38 :       do_ks = qs_ot_env(1)%settings%ks
     672          38 :       do_ener = qs_ot_env(1)%settings%do_ener
     673             : 
     674          38 :       IF (ASSOCIATED(qs_ot_env(1)%preconditioner)) THEN
     675          26 :          IF (.NOT. qs_ot_env(1)%use_dx) CPABORT("use dx")
     676          26 :          qs_ot_env(1)%gnorm = 0.0_dp
     677          26 :          IF (do_ks) THEN
     678          52 :             DO ispin = 1, nspin
     679             :                CALL apply_preconditioner(qs_ot_env(ispin)%preconditioner, &
     680          26 :                                          qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_dx)
     681          26 :                CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_dx, tmp)
     682          52 :                qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
     683             :             END DO
     684          26 :             IF (qs_ot_env(1)%gnorm .LT. 0.0_dp) THEN
     685           0 :                logger => cp_get_default_logger()
     686           0 :                WRITE (cp_logger_get_default_unit_nr(logger), *) "WARNING Preconditioner not positive definite !"
     687             :             END IF
     688          52 :             DO ispin = 1, nspin
     689          52 :                CALL dbcsr_scale(qs_ot_env(ispin)%matrix_dx, -1.0_dp)
     690             :             END DO
     691          26 :             IF (qs_ot_env(1)%settings%do_rotation) THEN
     692           0 :                DO ispin = 1, nspin
     693             :                   ! right now no preconditioner yet
     694           0 :                   CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_dx, qs_ot_env(ispin)%rot_mat_gx)
     695           0 :                   CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx, qs_ot_env(ispin)%rot_mat_dx, tmp)
     696             :                   ! added 0.5, because we have (antisymmetry) only half the number of variables
     697           0 :                   qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + 0.5_dp*tmp
     698             :                END DO
     699           0 :                DO ispin = 1, nspin
     700           0 :                   CALL dbcsr_scale(qs_ot_env(ispin)%rot_mat_dx, -1.0_dp)
     701             :                END DO
     702             :             END IF
     703             :          END IF
     704          26 :          IF (do_ener) THEN
     705           0 :             DO ispin = 1, nspin
     706           0 :                qs_ot_env(ispin)%ener_dx = qs_ot_env(ispin)%ener_gx
     707           0 :                tmp = DOT_PRODUCT(qs_ot_env(ispin)%ener_dx, qs_ot_env(ispin)%ener_gx)
     708           0 :                qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
     709           0 :                qs_ot_env(ispin)%ener_dx = -qs_ot_env(ispin)%ener_dx
     710             :             END DO
     711             :          END IF
     712             :       ELSE
     713          12 :          qs_ot_env(1)%gnorm = 0.0_dp
     714          12 :          IF (do_ks) THEN
     715          24 :             DO ispin = 1, nspin
     716          12 :                CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_gx, tmp)
     717          24 :                qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
     718             :             END DO
     719          12 :             IF (qs_ot_env(1)%settings%do_rotation) THEN
     720           0 :                DO ispin = 1, nspin
     721           0 :                   CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx, qs_ot_env(ispin)%rot_mat_gx, tmp)
     722             :                   ! added 0.5, because we have (antisymmetry) only half the number of variables
     723           0 :                   qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + 0.5_dp*tmp
     724             :                END DO
     725             :             END IF
     726             :          END IF
     727          12 :          IF (do_ener) THEN
     728           0 :             DO ispin = 1, nspin
     729           0 :                tmp = DOT_PRODUCT(qs_ot_env(ispin)%ener_gx, qs_ot_env(ispin)%ener_gx)
     730           0 :                qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
     731             :             END DO
     732             :          END IF
     733             :       END IF
     734             : 
     735          38 :       k = 0
     736          38 :       n = 0
     737          38 :       nener = 0
     738          38 :       IF (do_ks) THEN
     739          38 :          CALL dbcsr_get_info(qs_ot_env(1)%matrix_x, nfullrows_total=n)
     740          76 :          DO ispin = 1, nspin
     741          38 :             CALL dbcsr_get_info(qs_ot_env(ispin)%matrix_x, nfullcols_total=itmp)
     742          76 :             k = k + itmp
     743             :          END DO
     744             :       END IF
     745          38 :       IF (do_ener) THEN
     746           0 :          DO ispin = 1, nspin
     747           0 :             nener = nener + SIZE(qs_ot_env(ispin)%ener_x)
     748             :          END DO
     749             :       END IF
     750             :       ! Handling the case of no free variables to optimize
     751          38 :       IF (INT(n, KIND=int_8)*INT(k, KIND=int_8) + nener /= 0) THEN
     752          36 :          qs_ot_env(1)%delta = SQRT(ABS(qs_ot_env(1)%gnorm)/(INT(n, KIND=int_8)*INT(k, KIND=int_8) + nener))
     753          36 :          qs_ot_env(1)%gradient = -qs_ot_env(1)%gnorm
     754             :       ELSE
     755           2 :          qs_ot_env(1)%delta = 0.0_dp
     756           2 :          qs_ot_env(1)%gradient = 0.0_dp
     757             :       END IF
     758             : 
     759          38 :       CALL timestop(handle)
     760             : 
     761          38 :    END SUBROUTINE ot_new_sd_direction
     762             : 
     763             : !
     764             : ! creates a new CG direction. Implements Polak-Ribierre variant
     765             : ! using the preconditioner if associated
     766             : ! also updates the gradient for line search
     767             : !
     768             : ! **************************************************************************************************
     769             : !> \brief ...
     770             : !> \param qs_ot_env ...
     771             : ! **************************************************************************************************
     772       21102 :    SUBROUTINE ot_new_cg_direction(qs_ot_env)
     773             :       TYPE(qs_ot_type), DIMENSION(:), POINTER            :: qs_ot_env
     774             : 
     775             :       CHARACTER(len=*), PARAMETER :: routineN = 'ot_new_cg_direction'
     776             : 
     777             :       INTEGER                                            :: handle, ispin, itmp, k, n, nener, nspin
     778             :       LOGICAL                                            :: do_ener, do_ks
     779             :       REAL(KIND=dp)                                      :: beta_pr, gnorm_cross, test_down, tmp
     780             :       TYPE(cp_logger_type), POINTER                      :: logger
     781             : 
     782       21102 :       CALL timeset(routineN, handle)
     783             : 
     784       21102 :       nspin = SIZE(qs_ot_env)
     785       21102 :       logger => cp_get_default_logger()
     786             : 
     787       21102 :       do_ks = qs_ot_env(1)%settings%ks
     788       21102 :       do_ener = qs_ot_env(1)%settings%do_ener
     789             : 
     790       21102 :       gnorm_cross = 0.0_dp
     791       21102 :       IF (do_ks) THEN
     792       46707 :          DO ispin = 1, nspin
     793       25605 :             CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_gx_old, tmp)
     794       46707 :             gnorm_cross = gnorm_cross + tmp
     795             :          END DO
     796       21102 :          IF (qs_ot_env(1)%settings%do_rotation) THEN
     797        2458 :             DO ispin = 1, nspin
     798        1264 :                CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx, qs_ot_env(ispin)%rot_mat_gx_old, tmp)
     799             :                ! added 0.5, because we have (antisymmetry) only half the number of variables
     800        2458 :                gnorm_cross = gnorm_cross + 0.5_dp*tmp
     801             :             END DO
     802             :          END IF
     803             :       END IF
     804       21102 :       IF (do_ener) THEN
     805           0 :          DO ispin = 1, nspin
     806           0 :             tmp = DOT_PRODUCT(qs_ot_env(ispin)%ener_gx, qs_ot_env(ispin)%ener_gx_old)
     807           0 :             gnorm_cross = gnorm_cross + tmp
     808             :          END DO
     809             :       END IF
     810             : 
     811       21102 :       IF (ASSOCIATED(qs_ot_env(1)%preconditioner)) THEN
     812             : 
     813       35035 :          DO ispin = 1, nspin
     814             :             CALL apply_preconditioner(qs_ot_env(ispin)%preconditioner, &
     815       35035 :                                       qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_gx_old)
     816             :          END DO
     817       15506 :          qs_ot_env(1)%gnorm = 0.0_dp
     818       15506 :          IF (do_ks) THEN
     819       35035 :             DO ispin = 1, nspin
     820       19529 :                CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_gx_old, tmp)
     821       35035 :                qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
     822             :             END DO
     823       15506 :             IF (qs_ot_env(1)%gnorm .LT. 0.0_dp) THEN
     824           0 :                WRITE (cp_logger_get_default_unit_nr(logger), *) "WARNING Preconditioner not positive definite !"
     825             :             END IF
     826       35035 :             DO ispin = 1, nspin
     827       35035 :                CALL dbcsr_copy(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_gx_old)
     828             :             END DO
     829       15506 :             IF (qs_ot_env(1)%settings%do_rotation) THEN
     830        2458 :                DO ispin = 1, nspin
     831             :                   ! right now no preconditioner yet
     832        1264 :                   CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_gx_old, qs_ot_env(ispin)%rot_mat_gx)
     833        1264 :                   CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx, qs_ot_env(ispin)%rot_mat_gx_old, tmp)
     834             :                   ! added 0.5, because we have (antisymmetry) only half the number of variables
     835        2458 :                   qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + 0.5_dp*tmp
     836             :                END DO
     837        2458 :                DO ispin = 1, nspin
     838        2458 :                   CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_gx, qs_ot_env(ispin)%rot_mat_gx_old)
     839             :                END DO
     840             :             END IF
     841             :          END IF
     842       15506 :          IF (do_ener) THEN
     843           0 :             DO ispin = 1, nspin
     844           0 :                qs_ot_env(ispin)%ener_gx_old = qs_ot_env(ispin)%ener_gx
     845           0 :                tmp = DOT_PRODUCT(qs_ot_env(ispin)%ener_gx, qs_ot_env(ispin)%ener_gx_old)
     846           0 :                qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
     847           0 :                qs_ot_env(ispin)%ener_gx = qs_ot_env(ispin)%ener_gx_old
     848             :             END DO
     849             :          END IF
     850             :       ELSE
     851        5596 :          IF (do_ks) THEN
     852        5596 :             qs_ot_env(1)%gnorm = 0.0_dp
     853       11672 :             DO ispin = 1, nspin
     854        6076 :                CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_gx, tmp)
     855        6076 :                qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
     856       11672 :                CALL dbcsr_copy(qs_ot_env(ispin)%matrix_gx_old, qs_ot_env(ispin)%matrix_gx)
     857             :             END DO
     858        5596 :             IF (qs_ot_env(1)%settings%do_rotation) THEN
     859           0 :                DO ispin = 1, nspin
     860           0 :                   CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx, qs_ot_env(ispin)%rot_mat_gx, tmp)
     861             :                   ! added 0.5, because we have (antisymmetry) only half the number of variables
     862           0 :                   qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + 0.5_dp*tmp
     863           0 :                   CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_gx_old, qs_ot_env(ispin)%rot_mat_gx)
     864             :                END DO
     865             :             END IF
     866             :          END IF
     867        5596 :          IF (do_ener) THEN
     868           0 :             DO ispin = 1, nspin
     869           0 :                tmp = DOT_PRODUCT(qs_ot_env(ispin)%ener_gx, qs_ot_env(ispin)%ener_gx)
     870           0 :                qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
     871           0 :                qs_ot_env(ispin)%ener_gx_old = qs_ot_env(ispin)%ener_gx
     872             :             END DO
     873             :          END IF
     874             :       END IF
     875             : 
     876       21102 :       k = 0
     877       21102 :       n = 0
     878       21102 :       nener = 0
     879       21102 :       IF (do_ks) THEN
     880       21102 :          CALL dbcsr_get_info(qs_ot_env(1)%matrix_x, nfullrows_total=n)
     881       46707 :          DO ispin = 1, nspin
     882       25605 :             CALL dbcsr_get_info(qs_ot_env(ispin)%matrix_x, nfullcols_total=itmp)
     883       46707 :             k = k + itmp
     884             :          END DO
     885             :       END IF
     886       21102 :       IF (do_ener) THEN
     887           0 :          DO ispin = 1, nspin
     888           0 :             nener = nener + SIZE(qs_ot_env(ispin)%ener_x)
     889             :          END DO
     890             :       END IF
     891             :       ! Handling the case of no free variables to optimize
     892       21102 :       IF (INT(n, KIND=int_8)*INT(k, KIND=int_8) + nener /= 0) THEN
     893       21018 :          qs_ot_env(1)%delta = SQRT(ABS(qs_ot_env(1)%gnorm)/(INT(n, KIND=int_8)*INT(k, KIND=int_8) + nener))
     894       21018 :          beta_pr = (qs_ot_env(1)%gnorm - gnorm_cross)/qs_ot_env(1)%gnorm_old
     895             :       ELSE
     896          84 :          qs_ot_env(1)%delta = 0.0_dp
     897          84 :          beta_pr = 0.0_dp
     898             :       END IF
     899       21102 :       beta_pr = MAX(beta_pr, 0.0_dp) ! reset to SD
     900             : 
     901       21102 :       test_down = 0.0_dp
     902       21102 :       IF (do_ks) THEN
     903       46707 :          DO ispin = 1, nspin
     904             :             CALL dbcsr_add(qs_ot_env(ispin)%matrix_dx, qs_ot_env(ispin)%matrix_gx, &
     905       25605 :                            alpha_scalar=beta_pr, beta_scalar=-1.0_dp)
     906       25605 :             CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_dx, tmp)
     907       25605 :             test_down = test_down + tmp
     908       46707 :             IF (qs_ot_env(1)%settings%do_rotation) THEN
     909             :                CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_dx, qs_ot_env(ispin)%rot_mat_gx, &
     910        1264 :                               alpha_scalar=beta_pr, beta_scalar=-1.0_dp)
     911        1264 :                CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx, qs_ot_env(ispin)%rot_mat_dx, tmp)
     912        1264 :                test_down = test_down + 0.5_dp*tmp
     913             :             END IF
     914             :          END DO
     915             :       END IF
     916       21102 :       IF (do_ener) THEN
     917           0 :          DO ispin = 1, nspin
     918           0 :             qs_ot_env(ispin)%ener_dx = beta_pr*qs_ot_env(ispin)%ener_dx - qs_ot_env(ispin)%ener_gx
     919           0 :             tmp = DOT_PRODUCT(qs_ot_env(ispin)%ener_gx, qs_ot_env(ispin)%ener_dx)
     920           0 :             test_down = test_down + tmp
     921             :          END DO
     922             :       END IF
     923             : 
     924       21102 :       IF (test_down .GE. 0.0_dp) THEN ! reset to SD
     925         569 :          beta_pr = 0.0_dp
     926         569 :          IF (do_ks) THEN
     927        1301 :             DO ispin = 1, nspin
     928             :                CALL dbcsr_add(qs_ot_env(ispin)%matrix_dx, qs_ot_env(ispin)%matrix_gx, &
     929         732 :                               alpha_scalar=beta_pr, beta_scalar=-1.0_dp)
     930        1301 :                IF (qs_ot_env(1)%settings%do_rotation) THEN
     931             :                   CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_dx, &
     932          10 :                                  qs_ot_env(ispin)%rot_mat_gx, alpha_scalar=beta_pr, beta_scalar=-1.0_dp)
     933             :                END IF
     934             :             END DO
     935             :          END IF
     936         569 :          IF (do_ener) THEN
     937           0 :             DO ispin = 1, nspin
     938           0 :                qs_ot_env(ispin)%ener_dx = beta_pr*qs_ot_env(ispin)%ener_dx - qs_ot_env(ispin)%ener_gx
     939             :             END DO
     940             :          END IF
     941             :       END IF
     942             :       ! since we change the direction we have to adjust the gradient
     943       21102 :       qs_ot_env(1)%gradient = beta_pr*qs_ot_env(1)%gradient - qs_ot_env(1)%gnorm
     944       21102 :       qs_ot_env(1)%gnorm_old = qs_ot_env(1)%gnorm
     945             : 
     946       21102 :       CALL timestop(handle)
     947             : 
     948       21102 :    END SUBROUTINE ot_new_cg_direction
     949             : 
     950             : ! **************************************************************************************************
     951             : !> \brief ...
     952             : !> \param qs_ot_env ...
     953             : ! **************************************************************************************************
     954       40472 :    SUBROUTINE ot_diis_step(qs_ot_env)
     955             :       TYPE(qs_ot_type), DIMENSION(:), POINTER            :: qs_ot_env
     956             : 
     957             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'ot_diis_step'
     958             : 
     959             :       INTEGER                                            :: diis_bound, diis_m, handle, i, info, &
     960             :                                                             ispin, itmp, j, k, n, nener, nspin
     961             :       LOGICAL                                            :: do_ener, do_ks, do_ot_sd
     962             :       REAL(KIND=dp)                                      :: overlap, tmp, tr_xnew_gx, tr_xold_gx
     963             :       TYPE(cp_logger_type), POINTER                      :: logger
     964             : 
     965       40472 :       CALL timeset(routineN, handle)
     966             : 
     967       40472 :       logger => cp_get_default_logger()
     968             : 
     969       40472 :       do_ks = qs_ot_env(1)%settings%ks
     970       40472 :       do_ener = qs_ot_env(1)%settings%do_ener
     971       40472 :       nspin = SIZE(qs_ot_env)
     972             : 
     973       40472 :       diis_m = qs_ot_env(1)%settings%diis_m
     974             : 
     975       40472 :       IF (qs_ot_env(1)%diis_iter .LT. diis_m) THEN
     976       25410 :          diis_bound = qs_ot_env(1)%diis_iter + 1
     977             :       ELSE
     978             :          diis_bound = diis_m
     979             :       END IF
     980             : 
     981       40472 :       j = MOD(qs_ot_env(1)%diis_iter, diis_m) + 1 ! index in the circular array
     982             : 
     983             :       ! copy the position and the error vector in the diis buffers
     984             : 
     985       40472 :       IF (do_ks) THEN
     986       83936 :          DO ispin = 1, nspin
     987       43464 :             CALL dbcsr_copy(qs_ot_env(ispin)%matrix_h_x(j)%matrix, qs_ot_env(ispin)%matrix_x)
     988       83936 :             IF (qs_ot_env(ispin)%settings%do_rotation) THEN
     989         366 :                CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_h_x(j)%matrix, qs_ot_env(ispin)%rot_mat_x)
     990             :             END IF
     991             :          END DO
     992             :       END IF
     993       40472 :       IF (do_ener) THEN
     994           0 :          DO ispin = 1, nspin
     995           0 :             qs_ot_env(ispin)%ener_h_x(j, :) = qs_ot_env(ispin)%ener_x(:)
     996             :          END DO
     997             :       END IF
     998       40472 :       IF (ASSOCIATED(qs_ot_env(1)%preconditioner)) THEN
     999       35740 :          qs_ot_env(1)%gnorm = 0.0_dp
    1000       35740 :          IF (do_ks) THEN
    1001       74472 :             DO ispin = 1, nspin
    1002             :                CALL apply_preconditioner(qs_ot_env(ispin)%preconditioner, &
    1003       38732 :                                          qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_h_e(j)%matrix)
    1004             :                CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_h_e(j)%matrix, &
    1005       38732 :                               tmp)
    1006       74472 :                qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
    1007             :             END DO
    1008       35740 :             IF (qs_ot_env(1)%gnorm .LT. 0.0_dp) THEN
    1009           0 :                WRITE (cp_logger_get_default_unit_nr(logger), *) "WARNING Preconditioner not positive definite !"
    1010             :             END IF
    1011       74472 :             DO ispin = 1, nspin
    1012       74472 :                CALL dbcsr_scale(qs_ot_env(ispin)%matrix_h_e(j)%matrix, -qs_ot_env(1)%ds_min)
    1013             :             END DO
    1014       35740 :             IF (qs_ot_env(1)%settings%do_rotation) THEN
    1015         732 :                DO ispin = 1, nspin
    1016         366 :                   CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_h_e(j)%matrix, qs_ot_env(ispin)%rot_mat_gx)
    1017             :                   CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx, qs_ot_env(ispin)%rot_mat_h_e(j)%matrix, &
    1018         366 :                                  tmp)
    1019         732 :                   qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + 0.5_dp*tmp
    1020             :                END DO
    1021         732 :                DO ispin = 1, nspin
    1022         732 :                   CALL dbcsr_scale(qs_ot_env(ispin)%rot_mat_h_e(j)%matrix, -qs_ot_env(1)%ds_min)
    1023             :                END DO
    1024             :             END IF
    1025             :          END IF
    1026       35740 :          IF (do_ener) THEN
    1027           0 :             DO ispin = 1, nspin
    1028           0 :                qs_ot_env(ispin)%ener_h_e(j, :) = qs_ot_env(ispin)%ener_gx(:)
    1029           0 :                tmp = DOT_PRODUCT(qs_ot_env(ispin)%ener_h_e(j, :), qs_ot_env(ispin)%ener_gx(:))
    1030           0 :                qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
    1031           0 :                qs_ot_env(ispin)%ener_h_e(j, :) = -qs_ot_env(1)%ds_min*qs_ot_env(ispin)%ener_h_e(j, :)
    1032             :             END DO
    1033             :          END IF
    1034             :       ELSE
    1035        4732 :          qs_ot_env(1)%gnorm = 0.0_dp
    1036        4732 :          IF (do_ks) THEN
    1037        9464 :             DO ispin = 1, nspin
    1038        4732 :                CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_gx, tmp)
    1039        4732 :                qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
    1040             :                CALL dbcsr_add(qs_ot_env(ispin)%matrix_h_e(j)%matrix, &
    1041        9464 :                               qs_ot_env(ispin)%matrix_gx, alpha_scalar=0.0_dp, beta_scalar=-qs_ot_env(1)%ds_min)
    1042             :             END DO
    1043        4732 :             IF (qs_ot_env(1)%settings%do_rotation) THEN
    1044           0 :                DO ispin = 1, nspin
    1045           0 :                   CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx, qs_ot_env(ispin)%rot_mat_gx, tmp)
    1046           0 :                   qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + 0.5_dp*tmp
    1047             :                   CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_h_e(j)%matrix, &
    1048           0 :                                  qs_ot_env(ispin)%rot_mat_gx, alpha_scalar=0.0_dp, beta_scalar=-qs_ot_env(1)%ds_min)
    1049             :                END DO
    1050             :             END IF
    1051             :          END IF
    1052        4732 :          IF (do_ener) THEN
    1053           0 :             DO ispin = 1, nspin
    1054           0 :                tmp = DOT_PRODUCT(qs_ot_env(ispin)%ener_gx(:), qs_ot_env(ispin)%ener_gx(:))
    1055           0 :                qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
    1056           0 :                qs_ot_env(ispin)%ener_h_e(j, :) = -qs_ot_env(1)%ds_min*qs_ot_env(ispin)%ener_gx(:)
    1057             :             END DO
    1058             :          END IF
    1059             :       END IF
    1060       40472 :       k = 0
    1061       40472 :       n = 0
    1062       40472 :       nener = 0
    1063       40472 :       IF (do_ks) THEN
    1064       40472 :          CALL dbcsr_get_info(qs_ot_env(1)%matrix_x, nfullrows_total=n)
    1065       83936 :          DO ispin = 1, nspin
    1066       43464 :             CALL dbcsr_get_info(qs_ot_env(ispin)%matrix_x, nfullcols_total=itmp)
    1067       83936 :             k = k + itmp
    1068             :          END DO
    1069             :       END IF
    1070       40472 :       IF (do_ener) THEN
    1071           0 :          DO ispin = 1, nspin
    1072           0 :             nener = nener + SIZE(qs_ot_env(ispin)%ener_x)
    1073             :          END DO
    1074             :       END IF
    1075             :       ! Handling the case of no free variables to optimize
    1076       40472 :       IF (INT(n, KIND=int_8)*INT(k, KIND=int_8) + nener /= 0) THEN
    1077       40446 :          qs_ot_env(1)%delta = SQRT(ABS(qs_ot_env(1)%gnorm)/(INT(n, KIND=int_8)*INT(k, KIND=int_8) + nener))
    1078       40446 :          qs_ot_env(1)%gradient = -qs_ot_env(1)%gnorm
    1079             :       ELSE
    1080          26 :          qs_ot_env(1)%delta = 0.0_dp
    1081          26 :          qs_ot_env(1)%gradient = 0.0_dp
    1082             :       END IF
    1083             : 
    1084             :       ! make the diis matrix and solve it
    1085      244249 :       DO i = 1, diis_bound
    1086             :          ! I think there are two possible options, with and without preconditioner
    1087             :          ! as a metric
    1088             :          ! the second option seems most logical to me, and it seems marginally faster
    1089             :          ! in some of the tests
    1090             :          IF (.FALSE.) THEN
    1091             :             qs_ot_env(1)%ls_diis(i, j) = 0.0_dp
    1092             :             IF (do_ks) THEN
    1093             :                DO ispin = 1, nspin
    1094             :                   CALL dbcsr_dot(qs_ot_env(ispin)%matrix_h_e(j)%matrix, &
    1095             :                                  qs_ot_env(ispin)%matrix_h_e(i)%matrix, &
    1096             :                                  tmp)
    1097             :                   qs_ot_env(1)%ls_diis(i, j) = qs_ot_env(1)%ls_diis(i, j) + tmp
    1098             :                   IF (qs_ot_env(ispin)%settings%do_rotation) THEN
    1099             :                      CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_h_e(j)%matrix, &
    1100             :                                     qs_ot_env(ispin)%rot_mat_h_e(i)%matrix, &
    1101             :                                     tmp)
    1102             :                      qs_ot_env(1)%ls_diis(i, j) = qs_ot_env(1)%ls_diis(i, j) + 0.5_dp*tmp
    1103             :                   END IF
    1104             :                END DO
    1105             :             END IF
    1106             :             IF (do_ener) THEN
    1107             :                DO ispin = 1, nspin
    1108             :                   tmp = DOT_PRODUCT(qs_ot_env(ispin)%ener_h_e(j, :), qs_ot_env(ispin)%ener_h_e(i, :))
    1109             :                   qs_ot_env(1)%ls_diis(i, j) = qs_ot_env(1)%ls_diis(i, j) + tmp
    1110             :                END DO
    1111             :             END IF
    1112             :          ELSE
    1113      203777 :             qs_ot_env(1)%ls_diis(i, j) = 0.0_dp
    1114      203777 :             IF (do_ks) THEN
    1115      423838 :                DO ispin = 1, nspin
    1116             :                   CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, &
    1117             :                                  qs_ot_env(ispin)%matrix_h_e(i)%matrix, &
    1118      220061 :                                  tmp)
    1119      220061 :                   qs_ot_env(1)%ls_diis(i, j) = qs_ot_env(1)%ls_diis(i, j) - qs_ot_env(1)%ds_min*tmp
    1120      423838 :                   IF (qs_ot_env(ispin)%settings%do_rotation) THEN
    1121             :                      CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx, &
    1122             :                                     qs_ot_env(ispin)%rot_mat_h_e(i)%matrix, &
    1123        1976 :                                     tmp)
    1124        1976 :                      qs_ot_env(1)%ls_diis(i, j) = qs_ot_env(1)%ls_diis(i, j) - qs_ot_env(1)%ds_min*0.5_dp*tmp
    1125             :                   END IF
    1126             :                END DO
    1127             :             END IF
    1128      203777 :             IF (do_ener) THEN
    1129           0 :                DO ispin = 1, nspin
    1130           0 :                   tmp = DOT_PRODUCT(qs_ot_env(ispin)%ener_gx(:), qs_ot_env(ispin)%ener_h_e(i, :))
    1131           0 :                   qs_ot_env(1)%ls_diis(i, j) = qs_ot_env(1)%ls_diis(i, j) - qs_ot_env(1)%ds_min*tmp
    1132             :                END DO
    1133             :             END IF
    1134             :          END IF
    1135      203777 :          qs_ot_env(1)%ls_diis(j, i) = qs_ot_env(1)%ls_diis(i, j)
    1136      203777 :          qs_ot_env(1)%ls_diis(i, diis_bound + 1) = 1.0_dp
    1137      203777 :          qs_ot_env(1)%ls_diis(diis_bound + 1, i) = 1.0_dp
    1138      244249 :          qs_ot_env(1)%c_diis(i) = 0.0_dp
    1139             :       END DO
    1140       40472 :       qs_ot_env(1)%ls_diis(diis_bound + 1, diis_bound + 1) = 0.0_dp
    1141       40472 :       qs_ot_env(1)%c_diis(diis_bound + 1) = 1.0_dp
    1142             :       ! put in buffer, dgesv destroys
    1143     3077956 :       qs_ot_env(1)%lss_diis = qs_ot_env(1)%ls_diis
    1144             : 
    1145             :       CALL DGESV(diis_bound + 1, 1, qs_ot_env(1)%lss_diis, diis_m + 1, qs_ot_env(1)%ipivot, &
    1146       40472 :                  qs_ot_env(1)%c_diis, diis_m + 1, info)
    1147             : 
    1148       40472 :       IF (info .NE. 0) THEN
    1149           0 :          do_ot_sd = .TRUE.
    1150           0 :          WRITE (cp_logger_get_default_unit_nr(logger), *) "Singular DIIS matrix"
    1151             :       ELSE
    1152       40472 :          do_ot_sd = .FALSE.
    1153       40472 :          IF (do_ks) THEN
    1154       83936 :             DO ispin = 1, nspin
    1155             :                ! OK, add the vectors now
    1156       43464 :                CALL dbcsr_set(qs_ot_env(ispin)%matrix_x, 0.0_dp)
    1157      263525 :                DO i = 1, diis_bound
    1158             :                   CALL dbcsr_add(qs_ot_env(ispin)%matrix_x, &
    1159             :                                  qs_ot_env(ispin)%matrix_h_e(i)%matrix, &
    1160      263525 :                                  alpha_scalar=1.0_dp, beta_scalar=qs_ot_env(1)%c_diis(i))
    1161             :                END DO
    1162      263525 :                DO i = 1, diis_bound
    1163             :                   CALL dbcsr_add(qs_ot_env(ispin)%matrix_x, &
    1164             :                                  qs_ot_env(ispin)%matrix_h_x(i)%matrix, &
    1165      263525 :                                  alpha_scalar=1.0_dp, beta_scalar=qs_ot_env(1)%c_diis(i))
    1166             :                END DO
    1167       83936 :                IF (qs_ot_env(ispin)%settings%do_rotation) THEN
    1168         366 :                   CALL dbcsr_set(qs_ot_env(ispin)%rot_mat_x, 0.0_dp)
    1169        2342 :                   DO i = 1, diis_bound
    1170             :                      CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_x, &
    1171             :                                     qs_ot_env(ispin)%rot_mat_h_e(i)%matrix, &
    1172        2342 :                                     alpha_scalar=1.0_dp, beta_scalar=qs_ot_env(1)%c_diis(i))
    1173             :                   END DO
    1174        2342 :                   DO i = 1, diis_bound
    1175             :                      CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_x, &
    1176             :                                     qs_ot_env(ispin)%rot_mat_h_x(i)%matrix, &
    1177        2342 :                                     alpha_scalar=1.0_dp, beta_scalar=qs_ot_env(1)%c_diis(i))
    1178             :                   END DO
    1179             :                END IF
    1180             :             END DO
    1181             :          END IF
    1182       40472 :          IF (do_ener) THEN
    1183           0 :             DO ispin = 1, nspin
    1184           0 :                qs_ot_env(ispin)%ener_x(:) = 0.0_dp
    1185           0 :                DO i = 1, diis_bound
    1186             :                   qs_ot_env(ispin)%ener_x(:) = qs_ot_env(ispin)%ener_x(:) &
    1187           0 :                                                + qs_ot_env(1)%c_diis(i)*qs_ot_env(ispin)%ener_h_e(i, :)
    1188             :                END DO
    1189           0 :                DO i = 1, diis_bound
    1190             :                   qs_ot_env(ispin)%ener_x(:) = qs_ot_env(ispin)%ener_x(:) &
    1191           0 :                                                + qs_ot_env(1)%c_diis(i)*qs_ot_env(ispin)%ener_h_x(i, :)
    1192             :                END DO
    1193             :             END DO
    1194             :          END IF
    1195       40472 :          qs_ot_env(1)%diis_iter = qs_ot_env(1)%diis_iter + 1
    1196       40472 :          IF (qs_ot_env(1)%settings%safer_diis) THEN
    1197             :             ! now, final check, is the step in fact in the direction of the -gradient ?
    1198             :             ! if not we're walking towards a sadle point, and should avoid that
    1199             :             ! the direction of the step is x_new-x_old
    1200       40472 :             tr_xold_gx = 0.0_dp
    1201       40472 :             tr_xnew_gx = 0.0_dp
    1202       40472 :             IF (do_ks) THEN
    1203       83936 :                DO ispin = 1, nspin
    1204             :                   CALL dbcsr_dot(qs_ot_env(ispin)%matrix_h_x(j)%matrix, &
    1205       43464 :                                  qs_ot_env(ispin)%matrix_gx, tmp)
    1206       43464 :                   tr_xold_gx = tr_xold_gx + tmp
    1207             :                   CALL dbcsr_dot(qs_ot_env(ispin)%matrix_x, &
    1208       43464 :                                  qs_ot_env(ispin)%matrix_gx, tmp)
    1209       43464 :                   tr_xnew_gx = tr_xnew_gx + tmp
    1210       83936 :                   IF (qs_ot_env(ispin)%settings%do_rotation) THEN
    1211             :                      CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_h_x(j)%matrix, &
    1212         366 :                                     qs_ot_env(ispin)%rot_mat_gx, tmp)
    1213         366 :                      tr_xold_gx = tr_xold_gx + 0.5_dp*tmp
    1214             :                      CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_x, &
    1215         366 :                                     qs_ot_env(ispin)%rot_mat_gx, tmp)
    1216         366 :                      tr_xnew_gx = tr_xnew_gx + 0.5_dp*tmp
    1217             :                   END IF
    1218             :                END DO
    1219             :             END IF
    1220       40472 :             IF (do_ener) THEN
    1221           0 :                DO ispin = 1, nspin
    1222           0 :                   tmp = DOT_PRODUCT(qs_ot_env(ispin)%ener_h_x(j, :), qs_ot_env(ispin)%ener_gx(:))
    1223           0 :                   tr_xold_gx = tr_xold_gx + tmp
    1224           0 :                   tmp = DOT_PRODUCT(qs_ot_env(ispin)%ener_x(:), qs_ot_env(ispin)%ener_gx(:))
    1225           0 :                   tr_xnew_gx = tr_xnew_gx + tmp
    1226             :                END DO
    1227             :             END IF
    1228       40472 :             overlap = (tr_xnew_gx - tr_xold_gx)
    1229             :             ! OK, bad luck, take a SD step along the preconditioned gradient
    1230       40472 :             IF (overlap .GT. 0.0_dp) THEN
    1231             :                do_ot_sd = .TRUE.
    1232             :             END IF
    1233             :          END IF
    1234             :       END IF
    1235             : 
    1236             :       IF (do_ot_sd) THEN
    1237         840 :          qs_ot_env(1)%OT_METHOD_FULL = "OT SD"
    1238         840 :          IF (do_ks) THEN
    1239        1796 :             DO ispin = 1, nspin
    1240         956 :                CALL dbcsr_set(qs_ot_env(ispin)%matrix_x, 0.0_dp)
    1241             :                CALL dbcsr_add(qs_ot_env(ispin)%matrix_x, &
    1242             :                               qs_ot_env(ispin)%matrix_h_e(j)%matrix, &
    1243         956 :                               1.0_dp, 1.0_dp)
    1244             :                CALL dbcsr_add(qs_ot_env(ispin)%matrix_x, &
    1245             :                               qs_ot_env(ispin)%matrix_h_x(j)%matrix, &
    1246         956 :                               1.0_dp, 1.0_dp)
    1247        1796 :                IF (qs_ot_env(ispin)%settings%do_rotation) THEN
    1248          28 :                   CALL dbcsr_set(qs_ot_env(ispin)%rot_mat_x, 0.0_dp)
    1249             :                   CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_x, &
    1250             :                                  qs_ot_env(ispin)%rot_mat_h_e(j)%matrix, &
    1251          28 :                                  1.0_dp, 1.0_dp)
    1252             :                   CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_x, &
    1253             :                                  qs_ot_env(ispin)%rot_mat_h_x(j)%matrix, &
    1254          28 :                                  1.0_dp, 1.0_dp)
    1255             :                END IF
    1256             :             END DO
    1257             :          END IF
    1258         840 :          IF (do_ener) THEN
    1259           0 :             DO ispin = 1, nspin
    1260           0 :                qs_ot_env(ispin)%ener_x(:) = 0._dp
    1261           0 :                qs_ot_env(ispin)%ener_x(:) = qs_ot_env(ispin)%ener_x(:) + qs_ot_env(ispin)%ener_h_e(j, :)
    1262           0 :                qs_ot_env(ispin)%ener_x(:) = qs_ot_env(ispin)%ener_x(:) + qs_ot_env(ispin)%ener_h_x(j, :)
    1263             :             END DO
    1264             :          END IF
    1265             :       END IF
    1266             : 
    1267       40472 :       CALL timestop(handle)
    1268             : 
    1269       40472 :    END SUBROUTINE ot_diis_step
    1270             : 
    1271             : ! **************************************************************************************************
    1272             : !> \brief Energy minimizer by Broyden's method
    1273             : !> \param qs_ot_env variable to control minimizer behaviour
    1274             : !> \author Kurt Baarman (09.2010)
    1275             : ! **************************************************************************************************
    1276         176 :    SUBROUTINE ot_broyden_step(qs_ot_env)
    1277             :       TYPE(qs_ot_type), DIMENSION(:), POINTER            :: qs_ot_env
    1278             : 
    1279             :       INTEGER                                            :: diis_bound, diis_m, i, ispin, itmp, j, &
    1280             :                                                             k, n, nspin
    1281         176 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: circ_index
    1282             :       LOGICAL                                            :: adaptive_sigma, do_ener, do_ks, &
    1283             :                                                             enable_flip, forget_history
    1284             :       REAL(KIND=dp)                                      :: beta, eta, gamma, omega, sigma, &
    1285             :                                                             sigma_dec, sigma_min, tmp, tmp2
    1286         176 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: f, x
    1287         176 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: G, S
    1288             :       TYPE(cp_logger_type), POINTER                      :: logger
    1289             : 
    1290         176 :       eta = qs_ot_env(1)%settings%broyden_eta
    1291         176 :       omega = qs_ot_env(1)%settings%broyden_omega
    1292         176 :       sigma_dec = qs_ot_env(1)%settings%broyden_sigma_decrease
    1293         176 :       sigma_min = qs_ot_env(1)%settings%broyden_sigma_min
    1294         176 :       forget_history = qs_ot_env(1)%settings%broyden_forget_history
    1295         176 :       adaptive_sigma = qs_ot_env(1)%settings%broyden_adaptive_sigma
    1296         176 :       enable_flip = qs_ot_env(1)%settings%broyden_enable_flip
    1297             : 
    1298         176 :       do_ks = qs_ot_env(1)%settings%ks
    1299         176 :       do_ener = qs_ot_env(1)%settings%do_ener
    1300             : 
    1301         176 :       beta = qs_ot_env(1)%settings%broyden_beta
    1302         176 :       gamma = qs_ot_env(1)%settings%broyden_gamma
    1303         176 :       IF (adaptive_sigma) THEN
    1304         176 :          IF (qs_ot_env(1)%broyden_adaptive_sigma .LT. 0.0_dp) THEN
    1305           6 :             sigma = qs_ot_env(1)%settings%broyden_sigma
    1306             :          ELSE
    1307             :             sigma = qs_ot_env(1)%broyden_adaptive_sigma
    1308             :          END IF
    1309             :       ELSE
    1310           0 :          sigma = qs_ot_env(1)%settings%broyden_sigma
    1311             :       END IF
    1312             : 
    1313             :       ! simplify our life....
    1314         176 :       IF (do_ener .OR. .NOT. do_ks .OR. qs_ot_env(1)%settings%do_rotation) THEN
    1315           0 :          CPABORT("Not yet implemented")
    1316             :       END IF
    1317             :       !
    1318         176 :       nspin = SIZE(qs_ot_env)
    1319             : 
    1320         176 :       diis_m = qs_ot_env(1)%settings%diis_m
    1321             : 
    1322         176 :       IF (qs_ot_env(1)%diis_iter .LT. diis_m) THEN
    1323          84 :          diis_bound = qs_ot_env(1)%diis_iter + 1
    1324             :       ELSE
    1325          92 :          diis_bound = diis_m
    1326             :       END IF
    1327             : 
    1328             :       ! We want x:s, f:s and one random vector
    1329         176 :       k = 2*diis_bound + 1
    1330         704 :       ALLOCATE (S(k, k))
    1331         528 :       ALLOCATE (G(k, k))
    1332         528 :       ALLOCATE (f(k))
    1333         352 :       ALLOCATE (x(k))
    1334         528 :       ALLOCATE (circ_index(diis_bound))
    1335       30400 :       G = 0.0
    1336        2272 :       DO i = 1, k
    1337        2272 :          G(i, i) = sigma
    1338             :       END DO
    1339       30400 :       S = 0.0
    1340             : 
    1341         176 :       j = MOD(qs_ot_env(1)%diis_iter, diis_m) + 1 ! index in the circular array
    1342             : 
    1343         352 :       DO ispin = 1, nspin
    1344         352 :          CALL dbcsr_copy(qs_ot_env(ispin)%matrix_h_x(j)%matrix, qs_ot_env(ispin)%matrix_x)
    1345             :       END DO
    1346             : 
    1347         176 :       IF (ASSOCIATED(qs_ot_env(1)%preconditioner)) THEN
    1348         176 :          qs_ot_env(1)%gnorm = 0.0_dp
    1349         352 :          DO ispin = 1, nspin
    1350             :             CALL apply_preconditioner(qs_ot_env(ispin)%preconditioner, &
    1351         176 :                                       qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_h_e(j)%matrix)
    1352             :             CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_h_e(j)%matrix, &
    1353         176 :                            tmp)
    1354         352 :             qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
    1355             :          END DO
    1356         176 :          IF (qs_ot_env(1)%gnorm .LT. 0.0_dp) THEN
    1357           0 :             WRITE (cp_logger_get_default_unit_nr(logger), *) "WARNING Preconditioner not positive definite !"
    1358             :          END IF
    1359         352 :          DO ispin = 1, nspin
    1360         352 :             CALL dbcsr_scale(qs_ot_env(ispin)%matrix_h_e(j)%matrix, -1.0_dp)
    1361             :          END DO
    1362             :       ELSE
    1363           0 :          qs_ot_env(1)%gnorm = 0.0_dp
    1364           0 :          DO ispin = 1, nspin
    1365           0 :             CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_gx, tmp)
    1366           0 :             qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
    1367             :             CALL dbcsr_add(qs_ot_env(ispin)%matrix_h_e(j)%matrix, &
    1368           0 :                            qs_ot_env(ispin)%matrix_gx, alpha_scalar=0.0_dp, beta_scalar=-1.0_dp)
    1369             :          END DO
    1370             :       END IF
    1371             : 
    1372         176 :       k = 0
    1373             :       n = 0
    1374         176 :       CALL dbcsr_get_info(qs_ot_env(1)%matrix_x, nfullrows_total=n)
    1375         352 :       DO ispin = 1, nspin
    1376         176 :          CALL dbcsr_get_info(qs_ot_env(ispin)%matrix_x, nfullcols_total=itmp)
    1377         352 :          k = k + itmp
    1378             :       END DO
    1379             : 
    1380             :       ! Handling the case of no free variables to optimize
    1381         176 :       IF (INT(n, KIND=int_8)*INT(k, KIND=int_8) /= 0) THEN
    1382         176 :          qs_ot_env(1)%delta = SQRT(ABS(qs_ot_env(1)%gnorm)/(INT(n, KIND=int_8)*INT(k, KIND=int_8)))
    1383         176 :          qs_ot_env(1)%gradient = -qs_ot_env(1)%gnorm
    1384             :       ELSE
    1385           0 :          qs_ot_env(1)%delta = 0.0_dp
    1386           0 :          qs_ot_env(1)%gradient = 0.0_dp
    1387             :       END IF
    1388             : 
    1389         176 :       IF (diis_bound == diis_m) THEN
    1390         816 :          DO i = 1, diis_bound
    1391         816 :             circ_index(i) = MOD(j + i - 1, diis_m) + 1
    1392             :          END DO
    1393             :       ELSE
    1394         320 :          DO i = 1, diis_bound
    1395         320 :             circ_index(i) = i
    1396             :          END DO
    1397             :       END IF
    1398             : 
    1399       30400 :       S = 0.0_dp
    1400         352 :       DO ispin = 1, nspin
    1401         176 :          CALL dbcsr_init_random(qs_ot_env(ispin)%matrix_x)
    1402        1136 :          DO i = 1, diis_bound
    1403             :             CALL dbcsr_dot( &
    1404             :                qs_ot_env(ispin)%matrix_h_x(circ_index(i))%matrix, &
    1405         960 :                qs_ot_env(ispin)%matrix_h_x(circ_index(i))%matrix, tmp)
    1406         960 :             S(i, i) = S(i, i) + tmp
    1407             :             CALL dbcsr_dot( &
    1408             :                qs_ot_env(ispin)%matrix_h_e(circ_index(i))%matrix, &
    1409         960 :                qs_ot_env(ispin)%matrix_h_e(circ_index(i))%matrix, tmp)
    1410         960 :             S(i + diis_bound, i + diis_bound) = S(i + diis_bound, i + diis_bound) + tmp
    1411             :             CALL dbcsr_dot( &
    1412             :                qs_ot_env(ispin)%matrix_h_x(circ_index(i))%matrix, &
    1413         960 :                qs_ot_env(ispin)%matrix_x, tmp)
    1414         960 :             S(i, 2*diis_bound + 1) = S(i, 2*diis_bound + 1) + tmp
    1415         960 :             S(i, 2*diis_bound + 1) = S(2*diis_bound + 1, i)
    1416             :             CALL dbcsr_dot( &
    1417             :                qs_ot_env(ispin)%matrix_h_e(circ_index(i))%matrix, &
    1418         960 :                qs_ot_env(ispin)%matrix_x, tmp)
    1419         960 :             S(i + diis_bound, 2*diis_bound + 1) = S(i + diis_bound, 2*diis_bound + 1) + tmp
    1420         960 :             S(i + diis_bound, 2*diis_bound + 1) = S(2*diis_bound + 1, diis_bound + i)
    1421        3494 :             DO k = (i + 1), diis_bound
    1422             :                CALL dbcsr_dot( &
    1423             :                   qs_ot_env(ispin)%matrix_h_x(circ_index(i))%matrix, &
    1424             :                   qs_ot_env(ispin)%matrix_h_x(circ_index(k))%matrix, &
    1425        2534 :                   tmp)
    1426        2534 :                S(i, k) = S(i, k) + tmp
    1427        2534 :                S(k, i) = S(i, k)
    1428             :                CALL dbcsr_dot( &
    1429             :                   qs_ot_env(ispin)%matrix_h_e(circ_index(i))%matrix, &
    1430             :                   qs_ot_env(ispin)%matrix_h_e(circ_index(k))%matrix, &
    1431        2534 :                   tmp)
    1432        2534 :                S(diis_bound + i, diis_bound + k) = S(diis_bound + i, diis_bound + k) + tmp
    1433        3494 :                S(diis_bound + k, diis_bound + i) = S(diis_bound + i, diis_bound + k)
    1434             :             END DO
    1435        8124 :             DO k = 1, diis_bound
    1436             :                CALL dbcsr_dot( &
    1437             :                   qs_ot_env(ispin)%matrix_h_x(circ_index(i))%matrix, &
    1438        6028 :                   qs_ot_env(ispin)%matrix_h_e(circ_index(k))%matrix, tmp)
    1439        6028 :                S(i, k + diis_bound) = S(i, k + diis_bound) + tmp
    1440        6988 :                S(k + diis_bound, i) = S(i, k + diis_bound)
    1441             :             END DO
    1442             :          END DO
    1443         176 :          CALL dbcsr_dot(qs_ot_env(ispin)%matrix_x, qs_ot_env(ispin)%matrix_x, tmp)
    1444         352 :          S(2*diis_bound + 1, 2*diis_bound + 1) = S(2*diis_bound + 1, 2*diis_bound + 1) + tmp
    1445             :       END DO
    1446             : 
    1447             :       ! normalize
    1448         176 :       k = 2*diis_bound + 1
    1449         176 :       tmp = SQRT(S(k, k))
    1450        2272 :       S(k, :) = S(k, :)/tmp
    1451        2272 :       S(:, k) = S(:, k)/tmp
    1452             : 
    1453         176 :       IF (diis_bound .GT. 1) THEN
    1454         162 :          tmp = 0.0_dp
    1455         162 :          tmp2 = 0.0_dp
    1456         162 :          i = diis_bound
    1457         324 :          DO ispin = 1, nspin
    1458             :             ! dot product of differences
    1459             :             CALL dbcsr_dot( &
    1460             :                qs_ot_env(ispin)%matrix_h_x(circ_index(i))%matrix, &
    1461             :                qs_ot_env(ispin)%matrix_h_e(circ_index(i))%matrix, &
    1462         162 :                tmp)
    1463         162 :             tmp2 = tmp2 + tmp
    1464             :             CALL dbcsr_dot( &
    1465             :                qs_ot_env(ispin)%matrix_h_x(circ_index(i - 1))%matrix, &
    1466             :                qs_ot_env(ispin)%matrix_h_e(circ_index(i))%matrix, &
    1467         162 :                tmp)
    1468         162 :             tmp2 = tmp2 - tmp
    1469             :             CALL dbcsr_dot( &
    1470             :                qs_ot_env(ispin)%matrix_h_x(circ_index(i))%matrix, &
    1471             :                qs_ot_env(ispin)%matrix_h_e(circ_index(i - 1))%matrix, &
    1472         162 :                tmp)
    1473         162 :             tmp2 = tmp2 - tmp
    1474             :             CALL dbcsr_dot( &
    1475             :                qs_ot_env(ispin)%matrix_h_x(circ_index(i - 1))%matrix, &
    1476             :                qs_ot_env(ispin)%matrix_h_e(circ_index(i - 1))%matrix, &
    1477         162 :                tmp)
    1478         324 :             tmp2 = tmp2 + tmp
    1479             :          END DO
    1480         162 :          qs_ot_env(1)%c_broy(i - 1) = tmp2
    1481             :       END IF
    1482             : 
    1483         176 :       qs_ot_env(1)%energy_h(j) = qs_ot_env(1)%etotal
    1484             : 
    1485             :       ! If we went uphill, do backtracking line search
    1486        1136 :       i = MINLOC(qs_ot_env(1)%energy_h(1:diis_bound), dim=1)
    1487         176 :       IF (i .NE. j) THEN
    1488          26 :          sigma = sigma_dec*sigma
    1489          26 :          qs_ot_env(1)%OT_METHOD_FULL = "OT BTRK"
    1490          52 :          DO ispin = 1, nspin
    1491          26 :             CALL dbcsr_set(qs_ot_env(ispin)%matrix_x, 0.0_dp)
    1492             :             CALL dbcsr_add(qs_ot_env(ispin)%matrix_x, &
    1493             :                            qs_ot_env(ispin)%matrix_h_x(i)%matrix, &
    1494          26 :                            alpha_scalar=1.0_dp, beta_scalar=(1.0_dp - gamma))
    1495             :             CALL dbcsr_add(qs_ot_env(ispin)%matrix_x, &
    1496             :                            qs_ot_env(ispin)%matrix_h_x(circ_index(diis_bound))%matrix, &
    1497          52 :                            alpha_scalar=1.0_dp, beta_scalar=gamma)
    1498             :          END DO
    1499             :       ELSE
    1500             :          ! Construct G
    1501         778 :          DO i = 2, diis_bound
    1502        9208 :             f = 0.0
    1503        9208 :             x = 0.0
    1504             :             ! f is df_i
    1505         628 :             x(i) = 1.0
    1506         628 :             x(i - 1) = -1.0
    1507             :             ! x is dx_i
    1508         628 :             f(diis_bound + i) = 1.0
    1509         628 :             f(diis_bound + i - 1) = -1.0
    1510         628 :             tmp = 1.0_dp
    1511             :             ! We want a pos def Hessian
    1512         628 :             IF (enable_flip) THEN
    1513         628 :                IF (qs_ot_env(1)%c_broy(i - 1) .GT. 0) THEN
    1514             :                   !qs_ot_env(1)%OT_METHOD_FULL="OT FLIP"
    1515           2 :                   tmp = -1.0_dp
    1516             :                END IF
    1517             :             END IF
    1518             : 
    1519             :             ! get dx-Gdf
    1520      391524 :             x(:) = tmp*x - MATMUL(G, f)
    1521             :             ! dfSdf
    1522             :             ! we calculate matmul(S, f) twice. They're small...
    1523      391524 :             tmp = DOT_PRODUCT(f, MATMUL(S, f))
    1524             :             ! NOTE THAT S IS SYMMETRIC !!!
    1525      391524 :             f(:) = MATMUL(S, f)/tmp
    1526             :             ! the spread is an outer vector product
    1527      130658 :             G(:, :) = G + SPREAD(x, dim=2, ncopies=SIZE(f))*SPREAD(f, dim=1, ncopies=SIZE(x))
    1528             :          END DO
    1529        1856 :          f = 0.0_dp
    1530         150 :          f(2*diis_bound) = 1.0_dp
    1531       94380 :          x(:) = -beta*MATMUL(G, f)
    1532             : 
    1533             :          ! OK, add the vectors now, this sums up to the proposed step
    1534         300 :          DO ispin = 1, nspin
    1535         150 :             CALL dbcsr_set(qs_ot_env(ispin)%matrix_x, 0.0_dp)
    1536         928 :             DO i = 1, diis_bound
    1537             :                CALL dbcsr_add(qs_ot_env(ispin)%matrix_x, &
    1538             :                               qs_ot_env(ispin)%matrix_h_e(circ_index(i))%matrix, &
    1539         928 :                               alpha_scalar=1.0_dp, beta_scalar=-x(i + diis_bound))
    1540             :             END DO
    1541        1078 :             DO i = 1, diis_bound
    1542             :                CALL dbcsr_add(qs_ot_env(ispin)%matrix_x, &
    1543             :                               qs_ot_env(ispin)%matrix_h_x(circ_index(i))%matrix, &
    1544         928 :                               alpha_scalar=1.0_dp, beta_scalar=x(i))
    1545             :             END DO
    1546             :          END DO
    1547             : 
    1548         150 :          IF (adaptive_sigma) THEN
    1549         150 :             tmp = new_sigma(G, S, diis_bound)
    1550             :             !tmp = tmp * qs_ot_env ( 1 ) % settings % broyden_sigma
    1551         150 :             tmp = tmp*eta
    1552         150 :             sigma = MIN(omega*sigma, tmp)
    1553             :          END IF
    1554             : 
    1555             :          ! compute the inner product of direction of the step and gradient
    1556         150 :          tmp = 0.0_dp
    1557         300 :          DO ispin = 1, nspin
    1558             :             CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, &
    1559             :                            qs_ot_env(ispin)%matrix_x, &
    1560         150 :                            tmp2)
    1561         300 :             tmp = tmp + tmp2
    1562             :          END DO
    1563             : 
    1564         300 :          DO ispin = 1, nspin
    1565             :             ! if the direction of the step is not in direction of the gradient,
    1566             :             ! change step sign
    1567         300 :             IF (tmp .GE. 0.0_dp) THEN
    1568           8 :                qs_ot_env(1)%OT_METHOD_FULL = "OT TURN"
    1569           8 :                IF (forget_history) THEN
    1570           0 :                   qs_ot_env(1)%diis_iter = 0
    1571             :                END IF
    1572           8 :                sigma = sigma*sigma_dec
    1573             :                CALL dbcsr_add(qs_ot_env(ispin)%matrix_x, &
    1574             :                               qs_ot_env(ispin)%matrix_h_x(circ_index(diis_bound))%matrix, &
    1575           8 :                               alpha_scalar=-1.0_dp, beta_scalar=1.0_dp)
    1576             :             ELSE
    1577             :                CALL dbcsr_add(qs_ot_env(ispin)%matrix_x, &
    1578             :                               qs_ot_env(ispin)%matrix_h_x(circ_index(diis_bound))%matrix, &
    1579         142 :                               alpha_scalar=1.0_dp, beta_scalar=1.0_dp)
    1580             :             END IF
    1581             :          END DO
    1582             :       END IF
    1583             : 
    1584             :       ! get rid of S, G, f, x, circ_index for next round
    1585         176 :       DEALLOCATE (S, G, f, x, circ_index)
    1586             : 
    1587             :       ! update for next round
    1588         176 :       qs_ot_env(1)%diis_iter = qs_ot_env(1)%diis_iter + 1
    1589         176 :       qs_ot_env(1)%broyden_adaptive_sigma = MAX(sigma, sigma_min)
    1590             : 
    1591         352 :    END SUBROUTINE ot_broyden_step
    1592             : 
    1593             : ! **************************************************************************************************
    1594             : !> \brief ...
    1595             : !> \param G ...
    1596             : !> \param S ...
    1597             : !> \param n ...
    1598             : !> \return ...
    1599             : ! **************************************************************************************************
    1600         150 :    FUNCTION new_sigma(G, S, n) RESULT(sigma)
    1601             : !
    1602             : ! Calculate new sigma from eigenvalues of full size G by Arnoldi.
    1603             : !
    1604             : ! **************************************************************************************************
    1605             : 
    1606             :       REAL(KIND=dp), DIMENSION(:, :)                     :: G, S
    1607             :       INTEGER                                            :: n
    1608             :       REAL(KIND=dp)                                      :: sigma
    1609             : 
    1610             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: eigv
    1611         150 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: H
    1612             : 
    1613         600 :       ALLOCATE (H(n, n))
    1614         150 :       CALL hess_G(G, S, H, n)
    1615         450 :       ALLOCATE (eigv(n))
    1616         150 :       CALL diamat_all(H(1:n, 1:n), eigv)
    1617             : 
    1618             :       SELECT CASE (1)
    1619             :       CASE (1)
    1620             :          ! This estimator seems to work well. No theory.
    1621        1832 :          sigma = SUM(ABS(eigv**2))/SUM(ABS(eigv))
    1622             :       CASE (2)
    1623             :          ! Estimator based on Frobenius norm minimizer
    1624             :          sigma = SUM(ABS(eigv))/MAX(1, SIZE(eigv))
    1625             :       CASE (3)
    1626             :          ! Estimator based on induced 2-norm
    1627             :          sigma = (MAXVAL(ABS(eigv)) + MINVAL(ABS(eigv)))*0.5_dp
    1628             :       END SELECT
    1629             : 
    1630         150 :       DEALLOCATE (H, eigv)
    1631         150 :    END FUNCTION new_sigma
    1632             : 
    1633             : ! **************************************************************************************************
    1634             : !> \brief ...
    1635             : !> \param G ...
    1636             : !> \param S ...
    1637             : !> \param H ...
    1638             : !> \param n ...
    1639             : ! **************************************************************************************************
    1640         150 :    SUBROUTINE hess_G(G, S, H, n)
    1641             : !
    1642             : ! Make a hessenberg out of G into H. Cf Arnoldi.
    1643             : ! Inner product is weighted by S.
    1644             : ! Possible lucky breakdown at n.
    1645             : !
    1646             : ! **************************************************************************************************
    1647             :       REAL(KIND=dp), DIMENSION(:, :)                     :: G, S, H
    1648             :       INTEGER                                            :: n
    1649             : 
    1650             :       INTEGER                                            :: i, j, k
    1651             :       REAL(KIND=dp)                                      :: tmp
    1652         150 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: v
    1653         150 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: Q
    1654             : 
    1655         150 :       i = SIZE(G, 1)
    1656         150 :       k = SIZE(H, 1)
    1657         600 :       ALLOCATE (Q(i, k))
    1658         450 :       ALLOCATE (v(i))
    1659        5682 :       H = 0.0_dp
    1660       11214 :       Q = 0.0_dp
    1661             : 
    1662        1856 :       Q(:, 1) = 1.0_dp
    1663       27846 :       tmp = SQRT(DOT_PRODUCT(Q(:, 1), MATMUL(S, Q(:, 1))))
    1664       11214 :       Q(:, :) = Q(:, :)/tmp
    1665             : 
    1666         912 :       DO i = 1, k
    1667      161856 :          v(:) = MATMUL(G, Q(:, i))
    1668        3468 :          DO j = 1, i
    1669      656718 :             H(j, i) = DOT_PRODUCT(Q(:, j), MATMUL(S, v))
    1670       40974 :             v(:) = v - H(j, i)*Q(:, j)
    1671             :          END DO
    1672         912 :          IF (i .LT. k) THEN
    1673      146740 :             tmp = DOT_PRODUCT(v, MATMUL(S, v))
    1674         620 :             IF (tmp .LE. 0.0_dp) THEN
    1675           0 :                n = i
    1676           0 :                EXIT
    1677             :             END IF
    1678         620 :             tmp = SQRT(tmp)
    1679             :             ! Lucky breakdown
    1680         620 :             IF (ABS(tmp) .LT. 1e-9_dp) THEN
    1681           4 :                n = i
    1682           4 :                EXIT
    1683             :             END IF
    1684         616 :             H(i + 1, i) = tmp
    1685        9016 :             Q(:, i + 1) = v/H(i + 1, i)
    1686             :          END IF
    1687             :       END DO
    1688             : 
    1689         150 :       DEALLOCATE (Q, v)
    1690         150 :    END SUBROUTINE hess_G
    1691             : 
    1692        5356 : END MODULE qs_ot_minimizer

Generated by: LCOV version 1.15