LCOV - code coverage report
Current view: top level - src - qs_ot_minimizer.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:591cf04) Lines: 89.9 % 2081 1871
Test Date: 2026-09-21 02:17:57 Functions: 100.0 % 45 45

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2026 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \brief 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              :                                               dbcsr_type
      23              :    USE cp_dbcsr_contrib,                ONLY: dbcsr_dot,&
      24              :                                               dbcsr_init_random
      25              :    USE cp_log_handling,                 ONLY: cp_get_default_logger,&
      26              :                                               cp_logger_get_default_unit_nr,&
      27              :                                               cp_logger_type
      28              :    USE cp_output_handling,              ONLY: high_print_level
      29              :    USE ieee_arithmetic,                 ONLY: ieee_is_finite
      30              :    USE kinds,                           ONLY: dp,&
      31              :                                               int_8
      32              :    USE mathlib,                         ONLY: diamat_all
      33              :    USE message_passing,                 ONLY: mp_para_env_type
      34              :    USE preconditioner,                  ONLY: apply_preconditioner
      35              :    USE qs_ot,                           ONLY: qs_ot_get_derivative,&
      36              :                                               qs_ot_get_derivative_complex,&
      37              :                                               qs_ot_get_derivative_ref,&
      38              :                                               qs_ot_get_derivative_ref_complex
      39              :    USE qs_ot_types,                     ONLY: qs_ot_kpoint_preconditioner_scale,&
      40              :                                               qs_ot_type
      41              : #include "./base/base_uses.f90"
      42              : 
      43              :    IMPLICIT NONE
      44              : 
      45              :    PRIVATE
      46              : 
      47              :    PUBLIC  :: broyden_history_restart_required, &
      48              :               cg_history_restart_required, &
      49              :               lbfgs_curvature_damping_shift, &
      50              :               lbfgs_history_restart_required, &
      51              :               lbfgs_response_secant_parameters, &
      52              :               lbfgs_step_restart_required, &
      53              :               ot_mermin_response_assess, &
      54              :               ot_mermin_response_candidate_preferred, &
      55              :               ot_mermin_response_compare, &
      56              :               ot_mermin_response_preparation_needed, &
      57              :               ot_mermin_response_probe, &
      58              :               ot_mermin_response_shadow_followup, &
      59              :               ot_mermin_secant_curvature, &
      60              :               ot_mini, &
      61              :               ot_mini_prepare_gradient
      62              : 
      63              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_ot_minimizer'
      64              : 
      65              : CONTAINS
      66              : 
      67              : ! **************************************************************************************************
      68              : !> \brief Decide whether a non-descent Broyden step invalidates its secant history.
      69              : !> \param non_descent whether the proposed Broyden direction is not a descent direction
      70              : !> \param forget_history explicit user request to discard an inconsistent history
      71              : !> \param do_ener whether the product vector contains Mermin auxiliary-energy variables
      72              : !> \return true when the Broyden history has to be restarted
      73              : ! **************************************************************************************************
      74           16 :    PURE ELEMENTAL LOGICAL FUNCTION broyden_history_restart_required( &
      75              :       non_descent, forget_history, do_ener)
      76              :       LOGICAL, INTENT(IN)                                :: non_descent, forget_history, do_ener
      77              : 
      78           16 :       broyden_history_restart_required = non_descent .AND. (forget_history .OR. do_ener)
      79           16 :    END FUNCTION broyden_history_restart_required
      80              : 
      81              : ! **************************************************************************************************
      82              : !> \brief Decide whether an unresolved accepted energy change invalidates CG conjugacy.
      83              : !>
      84              : !> The occupation-preconditioned Mermin direction is a coupled Schur step rather than the action of
      85              : !> one fixed positive-definite metric on the physical gradient. Once the accepted free-energy change
      86              : !> is below floating-point resolution, its nonlinear conjugacy cannot be calibrated reliably. The
      87              : !> current preconditioned descent direction remains valid, but the history contribution is discarded.
      88              : !> \param occupation_preconditioned whether the product direction uses occupation preconditioning
      89              : !> \param current_energy current Mermin free energy
      90              : !> \param reference_energy Mermin free energy before the accepted line search
      91              : !> \return true when the CG history contribution has to be discarded
      92              : ! **************************************************************************************************
      93        23088 :    PURE ELEMENTAL LOGICAL FUNCTION cg_history_restart_required( &
      94              :       occupation_preconditioned, current_energy, reference_energy)
      95              :       LOGICAL, INTENT(IN)                                :: occupation_preconditioned
      96              :       REAL(KIND=dp), INTENT(IN)                          :: current_energy, reference_energy
      97              : 
      98              :       REAL(KIND=dp)                                      :: energy_scale
      99              : 
     100        23088 :       energy_scale = MAX(1.0_dp, ABS(current_energy), ABS(reference_energy))
     101              :       cg_history_restart_required = occupation_preconditioned .AND. &
     102              :                                     ABS(current_energy - reference_energy) <= &
     103        23088 :                                     64.0_dp*EPSILON(1.0_dp)*energy_scale
     104              : 
     105        23088 :    END FUNCTION cg_history_restart_required
     106              : 
     107              : !
     108              : ! the minimizer interface
     109              : ! should present all possible modes of minimization
     110              : ! these include CG SD DIIS
     111              : !
     112              : !
     113              : ! IN the case of nspin != 1 we have a gradient that is distributed over different qs_ot_env.
     114              : ! still things remain basically the same, since there are no constraints between the different qs_ot_env
     115              : ! we only should take care that the various scalar products are taken over the full vectors.
     116              : ! all the information needed and collected can be stored in the fist qs_ot_env only
     117              : ! (indicating that the data type for the gradient/position and minization should be separated)
     118              : !
     119              : ! **************************************************************************************************
     120              : !> \brief ...
     121              : !> \param qs_ot_env ...
     122              : !> \param matrix_hc ...
     123              : !> \param matrix_hc_im ...
     124              : !> \param matrix_hc_physical occupation-weighted derivative used for slopes and convergence
     125              : !> \param matrix_hc_physical_im imaginary component of matrix_hc_physical
     126              : !> \param para_env_inter_kp communicator between distributed k-point groups
     127              : !> \param gradient_only return after evaluating the current OT gradient
     128              : !> \param gradient_prepared reuse a gradient evaluated by ot_mini_prepare_gradient
     129              : ! **************************************************************************************************
     130        98426 :    SUBROUTINE ot_mini(qs_ot_env, matrix_hc, matrix_hc_im, &
     131              :                       matrix_hc_physical, matrix_hc_physical_im, para_env_inter_kp, &
     132              :                       gradient_only, gradient_prepared)
     133              :       TYPE(qs_ot_type), DIMENSION(:), POINTER            :: qs_ot_env
     134              :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_hc
     135              :       TYPE(dbcsr_p_type), DIMENSION(:), OPTIONAL, &
     136              :          POINTER                                         :: matrix_hc_im, matrix_hc_physical, &
     137              :                                                             matrix_hc_physical_im
     138              :       TYPE(mp_para_env_type), OPTIONAL, POINTER          :: para_env_inter_kp
     139              :       LOGICAL, INTENT(IN), OPTIONAL                      :: gradient_only, gradient_prepared
     140              : 
     141              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'ot_mini'
     142              : 
     143              :       INTEGER                                            :: handle, ispin, nspin
     144              :       LOGICAL                                            :: do_ener, do_ks, evaluate_gradient_only, &
     145              :                                                             reuse_gradient, &
     146              :                                                             separate_occupation_gradient
     147              :       REAL(KIND=dp)                                      :: tmp
     148              : 
     149        98426 :       CALL timeset(routineN, handle)
     150              : 
     151        98426 :       evaluate_gradient_only = .FALSE.
     152        98426 :       reuse_gradient = .FALSE.
     153        98426 :       IF (PRESENT(gradient_only)) evaluate_gradient_only = gradient_only
     154        98426 :       IF (PRESENT(gradient_prepared)) reuse_gradient = gradient_prepared
     155         2670 :       CPASSERT(.NOT. (evaluate_gradient_only .AND. reuse_gradient))
     156              : 
     157        98426 :       nspin = SIZE(qs_ot_env)
     158              : 
     159        98426 :       do_ks = qs_ot_env(1)%settings%ks
     160        98426 :       do_ener = qs_ot_env(1)%settings%do_ener
     161        98426 :       separate_occupation_gradient = PRESENT(matrix_hc_physical)
     162        98426 :       IF (separate_occupation_gradient) THEN
     163         2860 :          CPASSERT(qs_ot_env(1)%settings%occupation_preconditioner)
     164         2860 :          CPASSERT(SIZE(matrix_hc_physical) == nspin)
     165              :       END IF
     166              : 
     167        98426 :       qs_ot_env(1)%OT_METHOD_FULL = ""
     168              : 
     169              :       ! compute the gradient for the variables x
     170        98426 :       IF (.NOT. reuse_gradient .AND. .NOT. qs_ot_env(1)%energy_only) THEN
     171        74404 :          qs_ot_env(1)%gradient = 0.0_dp
     172       160478 :          DO ispin = 1, nspin
     173        86074 :             IF (do_ks) THEN
     174        86074 :                IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
     175         3277 :                   IF (.NOT. PRESENT(matrix_hc_im)) THEN
     176            0 :                      CPABORT("Complex k-point OT derivative requires imaginary H(k)*C(k).")
     177              :                   END IF
     178         4583 :                   SELECT CASE (qs_ot_env(1)%settings%ot_algorithm)
     179              :                   CASE ("TOD")
     180         1306 :                      IF (separate_occupation_gradient) THEN
     181          568 :                         CPASSERT(PRESENT(matrix_hc_physical_im))
     182              :                         CALL qs_ot_get_derivative_complex(matrix_hc(ispin)%matrix, &
     183              :                                                           matrix_hc_im(ispin)%matrix, &
     184              :                                                           qs_ot_env(ispin), &
     185              :                                                           matrix_hc_physical(ispin)%matrix, &
     186          568 :                                                           matrix_hc_physical_im(ispin)%matrix)
     187          568 :                         CPASSERT(ASSOCIATED(qs_ot_env(ispin)%matrix_preconditioned_gx))
     188          568 :                         CPASSERT(ASSOCIATED(qs_ot_env(ispin)%matrix_preconditioned_gx_im))
     189              :                         CALL dbcsr_copy(qs_ot_env(ispin)%matrix_preconditioned_gx, &
     190          568 :                                         qs_ot_env(ispin)%matrix_gx)
     191              :                         CALL dbcsr_copy(qs_ot_env(ispin)%matrix_preconditioned_gx_im, &
     192          568 :                                         qs_ot_env(ispin)%matrix_gx_im)
     193              :                         CALL qs_ot_get_derivative_complex(matrix_hc_physical(ispin)%matrix, &
     194              :                                                           matrix_hc_physical_im(ispin)%matrix, &
     195          568 :                                                           qs_ot_env(ispin))
     196              :                      ELSE
     197              :                         CALL qs_ot_get_derivative_complex(matrix_hc(ispin)%matrix, &
     198              :                                                           matrix_hc_im(ispin)%matrix, &
     199          738 :                                                           qs_ot_env(ispin))
     200              :                      END IF
     201              :                   CASE ("REF")
     202         1971 :                      IF (separate_occupation_gradient) THEN
     203          408 :                         CPASSERT(PRESENT(matrix_hc_physical_im))
     204              :                         CALL qs_ot_get_derivative_ref_complex(matrix_hc(ispin)%matrix, &
     205              :                                                               matrix_hc_im(ispin)%matrix, &
     206              :                                                               qs_ot_env(ispin), &
     207              :                                                               matrix_hc_physical(ispin)%matrix, &
     208          408 :                                                               matrix_hc_physical_im(ispin)%matrix)
     209          408 :                         CPASSERT(ASSOCIATED(qs_ot_env(ispin)%matrix_preconditioned_gx))
     210          408 :                         CPASSERT(ASSOCIATED(qs_ot_env(ispin)%matrix_preconditioned_gx_im))
     211              :                         CALL dbcsr_copy(qs_ot_env(ispin)%matrix_preconditioned_gx, &
     212          408 :                                         qs_ot_env(ispin)%matrix_gx)
     213              :                         CALL dbcsr_copy(qs_ot_env(ispin)%matrix_preconditioned_gx_im, &
     214          408 :                                         qs_ot_env(ispin)%matrix_gx_im)
     215              :                         CALL qs_ot_get_derivative_ref_complex(matrix_hc_physical(ispin)%matrix, &
     216              :                                                               matrix_hc_physical_im(ispin)%matrix, &
     217          408 :                                                               qs_ot_env(ispin))
     218              :                      ELSE
     219              :                         CALL qs_ot_get_derivative_ref_complex(matrix_hc(ispin)%matrix, &
     220              :                                                               matrix_hc_im(ispin)%matrix, &
     221         1563 :                                                               qs_ot_env(ispin))
     222              :                      END IF
     223              :                   CASE DEFAULT
     224         3277 :                      CPABORT("Complex k-point OT derivative requires ALGORITHM STRICT or IRAC")
     225              :                   END SELECT
     226              :                ELSE
     227       162246 :                   SELECT CASE (qs_ot_env(1)%settings%ot_algorithm)
     228              :                   CASE ("TOD")
     229              :                      CALL qs_ot_get_derivative(matrix_hc(ispin)%matrix, qs_ot_env(ispin)%matrix_x, &
     230              :                                                qs_ot_env(ispin)%matrix_sx, &
     231        79449 :                                                qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin))
     232        79449 :                      IF (separate_occupation_gradient) THEN
     233            0 :                         CPASSERT(ASSOCIATED(qs_ot_env(ispin)%matrix_preconditioned_gx))
     234              :                         CALL dbcsr_copy(qs_ot_env(ispin)%matrix_preconditioned_gx, &
     235            0 :                                         qs_ot_env(ispin)%matrix_gx)
     236              :                         CALL qs_ot_get_derivative(matrix_hc_physical(ispin)%matrix, &
     237              :                                                   qs_ot_env(ispin)%matrix_x, &
     238              :                                                   qs_ot_env(ispin)%matrix_sx, &
     239            0 :                                                   qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin))
     240              :                      END IF
     241              :                   CASE ("REF")
     242              :                      CALL qs_ot_get_derivative_ref(matrix_hc(ispin)%matrix, &
     243              :                                                    qs_ot_env(ispin)%matrix_x, qs_ot_env(ispin)%matrix_sx, &
     244         3348 :                                                    qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin))
     245         3348 :                      IF (separate_occupation_gradient) THEN
     246            0 :                         CPASSERT(ASSOCIATED(qs_ot_env(ispin)%matrix_preconditioned_gx))
     247              :                         CALL dbcsr_copy(qs_ot_env(ispin)%matrix_preconditioned_gx, &
     248            0 :                                         qs_ot_env(ispin)%matrix_gx)
     249              :                         CALL qs_ot_get_derivative_ref(matrix_hc_physical(ispin)%matrix, &
     250              :                                                       qs_ot_env(ispin)%matrix_x, &
     251              :                                                       qs_ot_env(ispin)%matrix_sx, &
     252            0 :                                                       qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin))
     253              :                      END IF
     254              :                   CASE DEFAULT
     255        82797 :                      CPABORT("ALGORITHM NYI")
     256              :                   END SELECT
     257              :                END IF
     258              :             END IF
     259              :             ! and also the gradient along the direction
     260       160478 :             IF (qs_ot_env(1)%use_dx) THEN
     261        81098 :                IF (do_ks) THEN
     262        81098 :                   CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_dx, tmp)
     263        81098 :                   qs_ot_env(1)%gradient = qs_ot_env(1)%gradient + tmp
     264        81098 :                   IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
     265         3229 :                      CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx_im, qs_ot_env(ispin)%matrix_dx_im, tmp)
     266         3229 :                      qs_ot_env(1)%gradient = qs_ot_env(1)%gradient + tmp
     267              :                   END IF
     268        81098 :                   IF (qs_ot_env(1)%settings%do_rotation) THEN
     269         3373 :                      CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx, qs_ot_env(ispin)%rot_mat_dx, tmp)
     270         3373 :                      qs_ot_env(1)%gradient = qs_ot_env(1)%gradient + 0.5_dp*tmp
     271         3373 :                      IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
     272              :                         CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx_im, &
     273         1491 :                                        qs_ot_env(ispin)%rot_mat_dx_im, tmp)
     274         1491 :                         qs_ot_env(1)%gradient = qs_ot_env(1)%gradient + 0.5_dp*tmp
     275              :                      END IF
     276              :                   END IF
     277              :                END IF
     278        81098 :                IF (do_ener) THEN
     279         9066 :                   tmp = DOT_PRODUCT(qs_ot_env(ispin)%ener_gx, qs_ot_env(ispin)%ener_dx)
     280         1054 :                   qs_ot_env(1)%gradient = qs_ot_env(1)%gradient + tmp
     281              :                END IF
     282              :             ELSE
     283         4976 :                IF (do_ks) THEN
     284         4976 :                   CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_gx, tmp)
     285         4976 :                   qs_ot_env(1)%gradient = qs_ot_env(1)%gradient - tmp
     286         4976 :                   IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
     287           48 :                      CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx_im, qs_ot_env(ispin)%matrix_gx_im, tmp)
     288           48 :                      qs_ot_env(1)%gradient = qs_ot_env(1)%gradient - tmp
     289              :                   END IF
     290         4976 :                   IF (qs_ot_env(1)%settings%do_rotation) THEN
     291            0 :                      CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx, qs_ot_env(ispin)%rot_mat_gx, tmp)
     292            0 :                      qs_ot_env(1)%gradient = qs_ot_env(1)%gradient - 0.5_dp*tmp
     293            0 :                      IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
     294              :                         CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx_im, &
     295            0 :                                        qs_ot_env(ispin)%rot_mat_gx_im, tmp)
     296            0 :                         qs_ot_env(1)%gradient = qs_ot_env(1)%gradient - 0.5_dp*tmp
     297              :                      END IF
     298              :                   END IF
     299              :                END IF
     300         4976 :                IF (do_ener) THEN
     301            0 :                   tmp = DOT_PRODUCT(qs_ot_env(ispin)%ener_gx, qs_ot_env(ispin)%ener_gx)
     302            0 :                   qs_ot_env(1)%gradient = qs_ot_env(1)%gradient - tmp
     303              :                END IF
     304              :             END IF
     305              :          END DO
     306        74404 :          CALL ot_mini_sum_kpoint_scalar(para_env_inter_kp, qs_ot_env(1)%gradient)
     307              :       END IF
     308              : 
     309        98426 :       IF (evaluate_gradient_only) THEN
     310         1582 :          CALL timestop(handle)
     311         1582 :          RETURN
     312              :       END IF
     313              : 
     314       141648 :       SELECT CASE (qs_ot_env(1)%settings%OT_METHOD)
     315              :       CASE ("CG")
     316        44804 :          IF (current_point_is_fine(qs_ot_env)) THEN
     317        23080 :             qs_ot_env(1)%OT_METHOD_FULL = "OT CG"
     318        23080 :             CALL ot_new_cg_direction(qs_ot_env, para_env_inter_kp)
     319        23080 :             qs_ot_env(1)%line_search_count = 0
     320              :          ELSE
     321        21724 :             qs_ot_env(1)%OT_METHOD_FULL = "OT LS"
     322              :          END IF
     323        44804 :          CALL do_line_search(qs_ot_env)
     324              :       CASE ("SD")
     325          206 :          IF (current_point_is_fine(qs_ot_env)) THEN
     326           64 :             qs_ot_env(1)%OT_METHOD_FULL = "OT SD"
     327           64 :             CALL ot_new_sd_direction(qs_ot_env, para_env_inter_kp)
     328           64 :             qs_ot_env(1)%line_search_count = 0
     329              :          ELSE
     330          142 :             qs_ot_env(1)%OT_METHOD_FULL = "OT LS"
     331              :          END IF
     332          206 :          CALL do_line_search(qs_ot_env)
     333              :       CASE ("DIIS")
     334        50452 :          qs_ot_env(1)%OT_METHOD_FULL = "OT DIIS"
     335        50452 :          CALL ot_diis_step(qs_ot_env, para_env_inter_kp)
     336              :       CASE ("BROY")
     337          206 :          qs_ot_env(1)%OT_METHOD_FULL = "OT BROY"
     338          206 :          CALL ot_broyden_step(qs_ot_env, para_env_inter_kp)
     339              :       CASE ("LBFG")
     340         1176 :          IF (current_point_is_fine(qs_ot_env)) THEN
     341          602 :             qs_ot_env(1)%OT_METHOD_FULL = "OT LBFGS"
     342          602 :             CALL ot_new_lbfgs_direction(qs_ot_env, para_env_inter_kp)
     343          602 :             qs_ot_env(1)%line_search_count = 0
     344              :          ELSE
     345          574 :             qs_ot_env(1)%OT_METHOD_FULL = "OT LS"
     346              :          END IF
     347         1176 :          CALL do_line_search(qs_ot_env)
     348              :       CASE DEFAULT
     349        96844 :          CPABORT("OT_METHOD NYI")
     350              :       END SELECT
     351              : 
     352        96844 :       CALL timestop(handle)
     353              : 
     354              :    END SUBROUTINE ot_mini
     355              : 
     356              : ! **************************************************************************************************
     357              : !> \brief Evaluate the current OT derivative without advancing the minimizer.
     358              : !> \param qs_ot_env OT channel environments
     359              : !> \param matrix_hc real H*C products
     360              : !> \param matrix_hc_im imaginary H*C products
     361              : !> \param matrix_hc_physical occupation-weighted real H*C products
     362              : !> \param matrix_hc_physical_im occupation-weighted imaginary H*C products
     363              : !> \param para_env_inter_kp communicator between distributed K-point groups
     364              : ! **************************************************************************************************
     365         1582 :    SUBROUTINE ot_mini_prepare_gradient(qs_ot_env, matrix_hc, matrix_hc_im, &
     366              :                                        matrix_hc_physical, matrix_hc_physical_im, para_env_inter_kp)
     367              :       TYPE(qs_ot_type), DIMENSION(:), POINTER            :: qs_ot_env
     368              :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_hc
     369              :       TYPE(dbcsr_p_type), DIMENSION(:), OPTIONAL, &
     370              :          POINTER                                         :: matrix_hc_im, matrix_hc_physical, &
     371              :                                                             matrix_hc_physical_im
     372              :       TYPE(mp_para_env_type), OPTIONAL, POINTER          :: para_env_inter_kp
     373              : 
     374              :       CALL ot_mini(qs_ot_env, matrix_hc, matrix_hc_im=matrix_hc_im, &
     375              :                    matrix_hc_physical=matrix_hc_physical, &
     376              :                    matrix_hc_physical_im=matrix_hc_physical_im, &
     377         1582 :                    para_env_inter_kp=para_env_inter_kp, gradient_only=.TRUE.)
     378              : 
     379         1582 :    END SUBROUTINE ot_mini_prepare_gradient
     380              : 
     381              : ! **************************************************************************************************
     382              : !> \brief Sum a minimizer scalar over distributed k-point groups when requested.
     383              : !> \param para_env_inter_kp communicator between distributed k-point groups
     384              : !> \param value scalar to sum
     385              : ! **************************************************************************************************
     386       646096 :    SUBROUTINE ot_mini_sum_kpoint_scalar(para_env_inter_kp, value)
     387              :       TYPE(mp_para_env_type), OPTIONAL, POINTER          :: para_env_inter_kp
     388              :       REAL(KIND=dp), INTENT(INOUT)                       :: value
     389              : 
     390       646096 :       IF (PRESENT(para_env_inter_kp)) THEN
     391        17764 :          IF (ASSOCIATED(para_env_inter_kp)) CALL para_env_inter_kp%sum(value)
     392              :       END IF
     393              : 
     394       646096 :    END SUBROUTINE ot_mini_sum_kpoint_scalar
     395              : 
     396              : ! **************************************************************************************************
     397              : !> \brief Assess a finite-response candidate at its accepted Mermin endpoint.
     398              : !> \param reference_energy Mermin energy at the start of the search
     399              : !> \param current_energy Mermin energy at the accepted endpoint
     400              : !> \param reference_residual physical residual at the start of the search
     401              : !> \param current_residual physical residual at the accepted endpoint
     402              : !> \param predicted_slope positive predicted decrease per unit line-search position
     403              : !> \param predicted_curvature signed finite-response curvature
     404              : !> \param position accepted line-search position
     405              : !> \param default_step configured initial line-search position
     406              : !> \param predicted_drop finite quadratic-model decrease
     407              : !> \param measured_drop measured Mermin decrease
     408              : !> \param quality measured over predicted decrease
     409              : !> \param residual_ratio endpoint over reference residual
     410              : !> \param good whether this is a resolved, useful accepted response sample
     411              : ! **************************************************************************************************
     412           26 :    PURE SUBROUTINE ot_mermin_response_assess( &
     413              :       reference_energy, current_energy, reference_residual, current_residual, &
     414              :       predicted_slope, predicted_curvature, position, default_step, &
     415              :       predicted_drop, measured_drop, quality, residual_ratio, good)
     416              :       REAL(KIND=dp), INTENT(IN) :: reference_energy, current_energy, reference_residual, &
     417              :          current_residual, predicted_slope, predicted_curvature, position, default_step
     418              :       REAL(KIND=dp), INTENT(OUT)                         :: predicted_drop, measured_drop, quality, &
     419              :                                                             residual_ratio
     420              :       LOGICAL, INTENT(OUT)                               :: good
     421              : 
     422              :       REAL(KIND=dp)                                      :: accepted_position, resolution, scale
     423              : 
     424           26 :       predicted_drop = 0.0_dp
     425           26 :       measured_drop = 0.0_dp
     426           26 :       quality = 0.0_dp
     427           26 :       residual_ratio = HUGE(1.0_dp)
     428           26 :       good = .FALSE.
     429              :       IF (.NOT. ieee_is_finite(reference_energy) .OR. .NOT. ieee_is_finite(current_energy) .OR. &
     430              :           .NOT. ieee_is_finite(reference_residual) .OR. .NOT. ieee_is_finite(current_residual) .OR. &
     431              :           .NOT. ieee_is_finite(predicted_slope) .OR. .NOT. ieee_is_finite(predicted_curvature) .OR. &
     432           26 :           .NOT. ieee_is_finite(position) .OR. .NOT. ieee_is_finite(default_step)) RETURN
     433              : 
     434           26 :       accepted_position = ABS(position)
     435           26 :       measured_drop = reference_energy - current_energy
     436              :       predicted_drop = accepted_position*predicted_slope - &
     437           26 :                        0.5_dp*accepted_position**2*predicted_curvature
     438              :       scale = MAX(1.0_dp, ABS(reference_energy), ABS(current_energy), &
     439           26 :                   ABS(predicted_drop), ABS(measured_drop))
     440           26 :       resolution = 256.0_dp*EPSILON(1.0_dp)*scale
     441           26 :       IF (reference_residual > TINY(reference_residual)) THEN
     442           26 :          residual_ratio = MAX(0.0_dp, current_residual)/reference_residual
     443              :       END IF
     444           26 :       IF (predicted_drop > resolution) quality = measured_drop/predicted_drop
     445              : 
     446              :       good = predicted_drop > resolution .AND. measured_drop > resolution .AND. &
     447              :              accepted_position >= 1.0E-6_dp*MAX(ABS(default_step), TINY(default_step)) .AND. &
     448           38 :              quality >= 0.05_dp .AND. quality <= 5.0_dp .AND. residual_ratio <= 1.0_dp
     449              : 
     450              :    END SUBROUTINE ot_mermin_response_assess
     451              : 
     452              : ! **************************************************************************************************
     453              : !> \brief Recover the total finite Mermin curvature of an accepted line-search secant.
     454              : !>
     455              : !>        For F(alpha)=F(0)-g*alpha+0.5*kappa*alpha**2, the accepted energy difference fixes
     456              : !>        kappa without separating REF, rotation, occupation, and self-consistent Hxc terms.
     457              : !> \param reference_energy Mermin energy at the start of the accepted search
     458              : !> \param current_energy Mermin energy at its accepted endpoint
     459              : !> \param predicted_slope positive directional decrease at the search origin
     460              : !> \param position accepted line-search position
     461              : !> \param curvature recovered total finite curvature
     462              : !> \param valid whether a resolved finite curvature was recovered
     463              : ! **************************************************************************************************
     464          114 :    PURE SUBROUTINE ot_mermin_secant_curvature( &
     465              :       reference_energy, current_energy, predicted_slope, position, curvature, valid)
     466              :       REAL(KIND=dp), INTENT(IN)                          :: reference_energy, current_energy, &
     467              :                                                             predicted_slope, position
     468              :       REAL(KIND=dp), INTENT(OUT)                         :: curvature
     469              :       LOGICAL, INTENT(OUT)                               :: valid
     470              : 
     471              :       REAL(KIND=dp)                                      :: accepted_position, measured_drop
     472              : 
     473          114 :       curvature = 0.0_dp
     474          114 :       valid = .FALSE.
     475              :       IF (.NOT. ieee_is_finite(reference_energy) .OR. .NOT. ieee_is_finite(current_energy) .OR. &
     476          114 :           .NOT. ieee_is_finite(predicted_slope) .OR. .NOT. ieee_is_finite(position)) RETURN
     477          114 :       accepted_position = ABS(position)
     478          114 :       IF (accepted_position <= SQRT(EPSILON(1.0_dp))) RETURN
     479              : 
     480          112 :       measured_drop = reference_energy - current_energy
     481          112 :       curvature = 2.0_dp*(accepted_position*predicted_slope - measured_drop)/accepted_position**2
     482          112 :       valid = ieee_is_finite(curvature)
     483          112 :       IF (.NOT. valid) curvature = 0.0_dp
     484              : 
     485              :    END SUBROUTINE ot_mermin_secant_curvature
     486              : 
     487              : ! **************************************************************************************************
     488              : !> \brief Compare an endpoint response shadow with the linear accepted-step model.
     489              : !> \param reference_energy Mermin energy at the start of the search
     490              : !> \param current_energy Mermin energy at the accepted endpoint
     491              : !> \param reference_residual physical residual at the start of the search
     492              : !> \param current_residual physical residual at the accepted endpoint
     493              : !> \param predicted_slope positive reference directional decrease
     494              : !> \param shadow_curvature endpoint finite-response curvature along the accepted direction
     495              : !> \param position accepted line-search position
     496              : !> \param advantage reduction of symmetric prediction error relative to the linear model
     497              : !> \param residual_ratio endpoint over reference residual
     498              : !> \param good whether the passive response prediction is both better and residual-consistent
     499              : ! **************************************************************************************************
     500          128 :    PURE SUBROUTINE ot_mermin_response_compare( &
     501              :       reference_energy, current_energy, reference_residual, current_residual, &
     502              :       predicted_slope, shadow_curvature, position, advantage, residual_ratio, good)
     503              :       REAL(KIND=dp), INTENT(IN) :: reference_energy, current_energy, reference_residual, &
     504              :          current_residual, predicted_slope, shadow_curvature, position
     505              :       REAL(KIND=dp), INTENT(OUT)                         :: advantage, residual_ratio
     506              :       LOGICAL, INTENT(OUT)                               :: good
     507              : 
     508              :       REAL(KIND=dp) :: accepted_position, baseline_drop, baseline_error, candidate_drop, &
     509              :          candidate_error, measured_drop, resolution, scale
     510              : 
     511          128 :       advantage = 0.0_dp
     512          128 :       residual_ratio = HUGE(1.0_dp)
     513          128 :       good = .FALSE.
     514              :       IF (.NOT. ieee_is_finite(reference_energy) .OR. .NOT. ieee_is_finite(current_energy) .OR. &
     515              :           .NOT. ieee_is_finite(reference_residual) .OR. .NOT. ieee_is_finite(current_residual) .OR. &
     516          128 :           .NOT. ieee_is_finite(predicted_slope) .OR. .NOT. ieee_is_finite(shadow_curvature) .OR. &
     517              :           .NOT. ieee_is_finite(position)) RETURN
     518              : 
     519          128 :       accepted_position = ABS(position)
     520          128 :       measured_drop = reference_energy - current_energy
     521          128 :       baseline_drop = accepted_position*predicted_slope
     522          128 :       candidate_drop = baseline_drop - 0.5_dp*accepted_position**2*shadow_curvature
     523              :       scale = MAX(1.0_dp, ABS(reference_energy), ABS(current_energy), ABS(measured_drop), &
     524          128 :                   ABS(baseline_drop), ABS(candidate_drop))
     525          128 :       resolution = 256.0_dp*EPSILON(1.0_dp)*scale
     526          128 :       IF (reference_residual > TINY(reference_residual)) THEN
     527          128 :          residual_ratio = MAX(0.0_dp, current_residual)/reference_residual
     528              :       END IF
     529          128 :       IF (measured_drop <= resolution .OR. baseline_drop <= resolution .OR. &
     530              :           candidate_drop <= resolution) RETURN
     531              : 
     532          128 :       baseline_error = ABS(measured_drop - baseline_drop)/scale
     533          128 :       candidate_error = ABS(measured_drop - candidate_drop)/scale
     534          128 :       advantage = baseline_error - candidate_error
     535          146 :       good = advantage > 64.0_dp*EPSILON(1.0_dp)*scale .AND. residual_ratio <= 1.05_dp
     536              : 
     537              :    END SUBROUTINE ot_mermin_response_compare
     538              : 
     539              : ! **************************************************************************************************
     540              : !> \brief Compare response and conventional directions in one accepted Mermin model.
     541              : !>
     542              : !>        The most recent accepted conventional secant supplies the dimensionless local curvature
     543              : !>        ratio kappa/g.  Applying that ratio to the current conventional slope transfers the
     544              : !>        measured line-search model without assuming that the two directions have equal norms.
     545              : !>        Both candidates are then evaluated at the same line-search position.
     546              : !> \param baseline_slope positive current conventional directional decrease
     547              : !> \param response_slope positive current response directional decrease
     548              : !> \param response_curvature current finite-response curvature
     549              : !> \param accepted_slope positive slope of the preceding accepted conventional search
     550              : !> \param accepted_curvature measured total curvature of that accepted search
     551              : !> \param position common line-search position used for comparison
     552              : !> \param baseline_drop predicted conventional Mermin decrease
     553              : !> \param response_drop predicted response Mermin decrease
     554              : !> \param relative_gain response improvement relative to the larger predicted decrease
     555              : !> \param preferred whether the response model predicts a resolved improvement
     556              : ! **************************************************************************************************
     557           30 :    PURE SUBROUTINE ot_mermin_response_candidate_preferred( &
     558              :       baseline_slope, response_slope, response_curvature, accepted_slope, accepted_curvature, &
     559              :       position, baseline_drop, response_drop, relative_gain, preferred)
     560              :       REAL(KIND=dp), INTENT(IN)                          :: baseline_slope, response_slope, &
     561              :                                                             response_curvature, accepted_slope, &
     562              :                                                             accepted_curvature, position
     563              :       REAL(KIND=dp), INTENT(OUT)                         :: baseline_drop, response_drop, &
     564              :                                                             relative_gain
     565              :       LOGICAL, INTENT(OUT)                               :: preferred
     566              : 
     567              :       REAL(KIND=dp)                                      :: alpha, baseline_curvature, &
     568              :                                                             curvature_ratio, resolution, scale
     569              : 
     570           30 :       baseline_drop = 0.0_dp
     571           30 :       response_drop = 0.0_dp
     572           30 :       relative_gain = 0.0_dp
     573           30 :       preferred = .FALSE.
     574              :       IF (.NOT. ieee_is_finite(baseline_slope) .OR. .NOT. ieee_is_finite(response_slope) .OR. &
     575              :           .NOT. ieee_is_finite(response_curvature) .OR. .NOT. ieee_is_finite(accepted_slope) .OR. &
     576           30 :           .NOT. ieee_is_finite(accepted_curvature) .OR. .NOT. ieee_is_finite(position)) RETURN
     577              : 
     578           30 :       alpha = ABS(position)
     579              :       scale = MAX(1.0_dp, ABS(baseline_slope), ABS(response_slope), &
     580           30 :                   ABS(response_curvature), ABS(accepted_slope), ABS(accepted_curvature))
     581           30 :       resolution = 256.0_dp*EPSILON(1.0_dp)*scale
     582              :       IF (alpha <= SQRT(EPSILON(1.0_dp)) .OR. baseline_slope <= resolution .OR. &
     583           30 :           response_slope <= resolution .OR. accepted_slope <= resolution) RETURN
     584              : 
     585           28 :       curvature_ratio = accepted_curvature/accepted_slope
     586           28 :       baseline_curvature = curvature_ratio*baseline_slope
     587           28 :       baseline_drop = alpha*baseline_slope - 0.5_dp*alpha**2*baseline_curvature
     588           28 :       response_drop = alpha*response_slope - 0.5_dp*alpha**2*response_curvature
     589           28 :       scale = MAX(ABS(baseline_drop), ABS(response_drop), resolution)
     590           28 :       relative_gain = (response_drop - baseline_drop)/scale
     591           36 :       preferred = response_drop > resolution .AND. response_drop > baseline_drop + resolution
     592              : 
     593              :    END SUBROUTINE ot_mermin_response_candidate_preferred
     594              : 
     595              : ! **************************************************************************************************
     596              : !> \brief Select a sparse coupled-response probe from accepted-history evidence.
     597              : !> \param available whether every local channel has a finite coupled response
     598              : !> \param residual current conventional-preconditioned residual
     599              : !> \param directions number of accepted directions seen by this response state
     600              : !> \param shadow_good_samples passive accepted steps where response improved the prediction
     601              : !> \param good_samples consecutive useful active response samples
     602              : !> \param cooldown accepted directions remaining after a failed response sample
     603              : !> \return whether the next direction should use the coupled response candidate
     604              : ! **************************************************************************************************
     605        23696 :    PURE FUNCTION ot_mermin_response_probe( &
     606              :       available, residual, directions, shadow_good_samples, good_samples, cooldown) RESULT(probe)
     607              :       LOGICAL, INTENT(IN)                                :: available
     608              :       REAL(KIND=dp), INTENT(IN)                          :: residual
     609              :       INTEGER, INTENT(IN)                                :: directions, shadow_good_samples, &
     610              :                                                             good_samples, cooldown
     611              :       LOGICAL                                            :: probe
     612              : 
     613              :       INTEGER                                            :: interval, phase
     614              : 
     615        23696 :       probe = .FALSE.
     616        23696 :       IF (.NOT. available .OR. .NOT. ieee_is_finite(residual)) RETURN
     617          114 :       IF (residual <= 0.0_dp .OR. residual > 2.0E-3_dp .OR. cooldown > 0) RETURN
     618          110 :       IF (shadow_good_samples < 3) RETURN
     619           52 :       interval = 8
     620           52 :       IF (good_samples >= 3) interval = 4
     621           52 :       IF (directions < interval) RETURN
     622           32 :       phase = MOD(directions, interval)
     623           32 :       probe = phase == 0 .OR. phase == 1
     624              : 
     625           32 :    END FUNCTION ot_mermin_response_probe
     626              : 
     627              : ! **************************************************************************************************
     628              : !> \brief Decide whether the next accepted state needs the dense finite Mermin response.
     629              : !>
     630              : !>        A pending shadow is always completed. Otherwise the response is prepared while collecting
     631              : !>        the initial accepted-step calibration and at the state immediately preceding a sparse
     632              : !>        response-probe window. The relaxed residual bound accounts for using the preceding
     633              : !>        accepted residual before the current norm has been reduced across K-point groups.
     634              : !> \param residual preceding accepted conventional-preconditioned residual
     635              : !> \param directions number of accepted directions already seen
     636              : !> \param shadow_good_samples useful passive accepted-step samples
     637              : !> \param good_samples useful active response samples
     638              : !> \param cooldown accepted directions remaining after a failed active sample
     639              : !> \param shadow_pending whether the current endpoint must assess a prepared shadow
     640              : !> \return whether to build the dense finite response at the current accepted endpoint
     641              : ! **************************************************************************************************
     642          368 :    PURE FUNCTION ot_mermin_response_preparation_needed( &
     643              :       residual, directions, shadow_good_samples, good_samples, cooldown, shadow_pending) RESULT(prepare)
     644              :       REAL(KIND=dp), INTENT(IN)                          :: residual
     645              :       INTEGER, INTENT(IN)                                :: directions, shadow_good_samples, &
     646              :                                                             good_samples, cooldown
     647              :       LOGICAL, INTENT(IN)                                :: shadow_pending
     648              :       LOGICAL                                            :: prepare
     649              : 
     650              :       INTEGER                                            :: interval, next_direction, phase
     651              : 
     652          368 :       prepare = shadow_pending
     653          368 :       IF (prepare) RETURN
     654          242 :       IF (.NOT. ieee_is_finite(residual) .OR. residual <= 0.0_dp .OR. residual > 4.0E-3_dp) RETURN
     655          166 :       IF (cooldown > 1) RETURN
     656          148 :       IF (shadow_good_samples < 3) THEN
     657          368 :          prepare = .TRUE.
     658              :          RETURN
     659              :       END IF
     660              : 
     661           74 :       interval = 8
     662           74 :       IF (good_samples >= 3) interval = 4
     663           74 :       next_direction = MIN(HUGE(directions) - 1, MAX(0, directions) + 1)
     664           74 :       phase = MOD(next_direction, interval)
     665           74 :       prepare = phase == interval - 1
     666              : 
     667           74 :    END FUNCTION ot_mermin_response_preparation_needed
     668              : 
     669              : ! **************************************************************************************************
     670              : !> \brief Decide whether a prepared conventional direction needs a shadow at its endpoint.
     671              : !> \param residual current conventional-preconditioned residual
     672              : !> \param directions number of accepted directions including the current one
     673              : !> \param shadow_good_samples useful passive accepted-step samples
     674              : !> \param good_samples useful active response samples
     675              : !> \param cooldown accepted directions remaining after a failed active sample
     676              : !> \return whether the next accepted endpoint must assess the current response shadow
     677              : ! **************************************************************************************************
     678          162 :    PURE FUNCTION ot_mermin_response_shadow_followup( &
     679              :       residual, directions, shadow_good_samples, good_samples, cooldown) RESULT(followup)
     680              :       REAL(KIND=dp), INTENT(IN)                          :: residual
     681              :       INTEGER, INTENT(IN)                                :: directions, shadow_good_samples, &
     682              :                                                             good_samples, cooldown
     683              :       LOGICAL                                            :: followup
     684              : 
     685              :       INTEGER                                            :: interval, phase
     686              : 
     687          162 :       followup = .FALSE.
     688          162 :       IF (.NOT. ieee_is_finite(residual) .OR. residual <= 0.0_dp .OR. residual > 4.0E-3_dp) RETURN
     689          162 :       IF (cooldown > 1) RETURN
     690          162 :       IF (shadow_good_samples < 3) THEN
     691          162 :          followup = .TRUE.
     692              :          RETURN
     693              :       END IF
     694              : 
     695           56 :       interval = 8
     696           56 :       IF (good_samples >= 3) interval = 4
     697           56 :       phase = MOD(MAX(0, directions), interval)
     698           56 :       followup = phase == interval - 1 .OR. phase == 0
     699              : 
     700              :    END FUNCTION ot_mermin_response_shadow_followup
     701              : 
     702              : ! **************************************************************************************************
     703              : !> \brief Assess and optionally select a calibrated finite Mermin response direction.
     704              : !>
     705              : !>        The caller supplies its conventional descent direction in the product workspaces.  A
     706              : !>        finite-response direction is considered only after accepted conventional steps have
     707              : !>        calibrated its quadratic model.  This keeps the response independent of the line-search
     708              : !>        minimizer while preserving the physical residual as the convergence measure.
     709              : !> \param qs_ot_env OT environments for all local spin/k-point channels
     710              : !> \param para_env_inter_kp communicator between distributed k-point groups
     711              : !> \param baseline_delta conventional preconditioned residual
     712              : !> \param test_down physical gradient dotted into the conventional direction, updated on selection
     713              : !> \param use_response_candidate whether the finite-response direction was selected
     714              : ! **************************************************************************************************
     715        23682 :    SUBROUTINE ot_try_mermin_response_direction( &
     716              :       qs_ot_env, para_env_inter_kp, baseline_delta, test_down, use_response_candidate)
     717              :       TYPE(qs_ot_type), DIMENSION(:), POINTER            :: qs_ot_env
     718              :       TYPE(mp_para_env_type), OPTIONAL, POINTER          :: para_env_inter_kp
     719              :       REAL(KIND=dp), INTENT(IN)                          :: baseline_delta
     720              :       REAL(KIND=dp), INTENT(INOUT)                       :: test_down
     721              :       LOGICAL, INTENT(OUT)                               :: use_response_candidate
     722              : 
     723              :       INTEGER                                            :: ispin, nspin
     724              :       LOGICAL :: active_candidate_available, candidate_available, candidate_good, do_ener, do_ks, &
     725              :          probe_response_candidate, shadow_good
     726              :       REAL(KIND=dp) :: baseline_model_drop, measured_drop, predicted_drop, response_advantage, &
     727              :          response_model_drop, response_quality, response_relative_gain, response_residual_ratio, &
     728              :          response_test_down, tmp
     729              :       TYPE(cp_logger_type), POINTER                      :: logger
     730              : 
     731        23682 :       nspin = SIZE(qs_ot_env)
     732        23682 :       do_ks = qs_ot_env(1)%settings%ks
     733        23682 :       do_ener = qs_ot_env(1)%settings%do_ener
     734        23682 :       logger => cp_get_default_logger()
     735        23682 :       shadow_good = .FALSE.
     736        23682 :       candidate_good = .FALSE.
     737              : 
     738        23682 :       IF (qs_ot_env(1)%response_shadow_pending) THEN
     739              :          CALL ot_mermin_response_compare( &
     740              :             qs_ot_env(1)%response_reference_energy, qs_ot_env(1)%etotal, &
     741              :             qs_ot_env(1)%response_reference_residual, baseline_delta, &
     742              :             qs_ot_env(1)%response_predicted_slope, qs_ot_env(1)%response_shadow_curvature, &
     743          124 :             qs_ot_env(1)%ds_min, response_advantage, response_residual_ratio, shadow_good)
     744          124 :          IF (shadow_good) THEN
     745              :             qs_ot_env(1)%response_shadow_good_samples = &
     746              :                MIN(HUGE(qs_ot_env(1)%response_shadow_good_samples) - 1, &
     747          108 :                    qs_ot_env(1)%response_shadow_good_samples + 1)
     748              :          ELSE
     749              :             qs_ot_env(1)%response_shadow_good_samples = &
     750           16 :                MAX(0, qs_ot_env(1)%response_shadow_good_samples - 1)
     751              :          END IF
     752          124 :          IF (logger%iter_info%print_level >= high_print_level .AND. logger%para_env%is_source()) THEN
     753              :             WRITE (cp_logger_get_default_unit_nr(logger), &
     754              :                    '(A,1X,I5,2(1X,L1),4(1X,ES16.8))') &
     755            0 :                " OT Mermin response shadow good hxc-dir advantage residual model shadow:", &
     756            0 :                qs_ot_env(1)%response_shadow_good_samples, shadow_good, &
     757            0 :                qs_ot_env(1)%response_hxc_direction_valid, response_advantage, &
     758            0 :                response_residual_ratio, qs_ot_env(1)%response_model_curvature, &
     759            0 :                qs_ot_env(1)%response_shadow_curvature
     760              :          END IF
     761          124 :          qs_ot_env(1)%response_shadow_pending = .FALSE.
     762              :       END IF
     763              : 
     764        23682 :       IF (qs_ot_env(1)%response_candidate_pending) THEN
     765              :          CALL ot_mermin_response_assess( &
     766              :             qs_ot_env(1)%response_reference_energy, qs_ot_env(1)%etotal, &
     767              :             qs_ot_env(1)%response_reference_residual, baseline_delta, &
     768              :             qs_ot_env(1)%response_predicted_slope, qs_ot_env(1)%response_predicted_curvature, &
     769              :             qs_ot_env(1)%ds_min, qs_ot_env(1)%settings%ds_min, predicted_drop, measured_drop, &
     770           16 :             response_quality, response_residual_ratio, candidate_good)
     771           16 :          IF (candidate_good) THEN
     772              :             qs_ot_env(1)%response_candidate_good_samples = &
     773              :                MIN(HUGE(qs_ot_env(1)%response_candidate_good_samples) - 1, &
     774           12 :                    qs_ot_env(1)%response_candidate_good_samples + 1)
     775              :          ELSE
     776              :             qs_ot_env(1)%response_candidate_good_samples = &
     777            4 :                MAX(0, qs_ot_env(1)%response_candidate_good_samples - 2)
     778            4 :             qs_ot_env(1)%response_candidate_cooldown = 6
     779              :          END IF
     780           16 :          IF (logger%iter_info%print_level >= high_print_level .AND. logger%para_env%is_source()) THEN
     781              :             WRITE (cp_logger_get_default_unit_nr(logger), '(A,1X,I5,1X,L1,4(1X,ES16.8))') &
     782            0 :                " OT Mermin response candidate good quality residual predicted measured:", &
     783            0 :                qs_ot_env(1)%response_candidate_good_samples, candidate_good, response_quality, &
     784            0 :                response_residual_ratio, predicted_drop, measured_drop
     785              :          END IF
     786           16 :          qs_ot_env(1)%response_candidate_pending = .FALSE.
     787              :       END IF
     788              : 
     789              :       qs_ot_env(1)%response_candidate_directions = &
     790              :          MIN(HUGE(qs_ot_env(1)%response_candidate_directions) - 1, &
     791        23682 :              qs_ot_env(1)%response_candidate_directions + 1)
     792        23682 :       IF (qs_ot_env(1)%response_candidate_cooldown > 0) THEN
     793           24 :          qs_ot_env(1)%response_candidate_cooldown = qs_ot_env(1)%response_candidate_cooldown - 1
     794              :       END IF
     795              : 
     796              :       candidate_available = qs_ot_env(1)%settings%occupation_preconditioner .AND. &
     797        23682 :                             qs_ot_env(1)%settings%do_rotation .AND. do_ener
     798        53052 :       DO ispin = 1, nspin
     799              :          candidate_available = candidate_available .AND. &
     800              :                                qs_ot_env(ispin)%rotation_response_valid .AND. &
     801              :                                ASSOCIATED(qs_ot_env(ispin)%matrix_response_gx) .AND. &
     802              :                                ASSOCIATED(qs_ot_env(ispin)%matrix_response_gx_im) .AND. &
     803              :                                ASSOCIATED(qs_ot_env(ispin)%rot_mat_response_gx) .AND. &
     804              :                                ASSOCIATED(qs_ot_env(ispin)%rot_mat_response_gx_im) .AND. &
     805        82180 :                                ASSOCIATED(qs_ot_env(ispin)%ener_response_gx)
     806              :       END DO
     807              :       active_candidate_available = candidate_available .AND. shadow_good .AND. &
     808        23682 :                                    qs_ot_env(1)%response_hxc_direction_valid
     809              :       probe_response_candidate = ot_mermin_response_probe( &
     810              :                                  active_candidate_available, baseline_delta, &
     811              :                                  qs_ot_env(1)%response_candidate_directions, &
     812              :                                  qs_ot_env(1)%response_shadow_good_samples, &
     813              :                                  qs_ot_env(1)%response_candidate_good_samples, &
     814        23682 :                                  qs_ot_env(1)%response_candidate_cooldown)
     815        23682 :       use_response_candidate = .FALSE.
     816              : 
     817        23682 :       IF (probe_response_candidate) THEN
     818           22 :          response_test_down = 0.0_dp
     819           22 :          baseline_model_drop = 0.0_dp
     820           22 :          response_model_drop = 0.0_dp
     821           22 :          response_relative_gain = 0.0_dp
     822           22 :          IF (do_ks) THEN
     823           54 :             DO ispin = 1, nspin
     824              :                CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, &
     825           32 :                               qs_ot_env(ispin)%matrix_response_gx, tmp)
     826           32 :                response_test_down = response_test_down - tmp
     827           32 :                IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
     828              :                   CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx_im, &
     829           32 :                                  qs_ot_env(ispin)%matrix_response_gx_im, tmp)
     830           32 :                   response_test_down = response_test_down - tmp
     831              :                END IF
     832              :                CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx, &
     833           32 :                               qs_ot_env(ispin)%rot_mat_response_gx, tmp)
     834           32 :                response_test_down = response_test_down - 0.5_dp*tmp
     835           86 :                IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
     836              :                   CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx_im, &
     837           32 :                                  qs_ot_env(ispin)%rot_mat_response_gx_im, tmp)
     838           32 :                   response_test_down = response_test_down - 0.5_dp*tmp
     839              :                END IF
     840              :             END DO
     841              :          END IF
     842           22 :          IF (do_ener) THEN
     843           54 :             DO ispin = 1, nspin
     844              :                response_test_down = response_test_down - &
     845              :                                     DOT_PRODUCT(qs_ot_env(ispin)%ener_gx, &
     846          222 :                                                 qs_ot_env(ispin)%ener_response_gx)
     847              :             END DO
     848              :          END IF
     849           22 :          CALL ot_mini_sum_kpoint_scalar(para_env_inter_kp, response_test_down)
     850           22 :          IF (response_test_down < 0.0_dp) THEN
     851              :             CALL ot_mermin_response_candidate_preferred( &
     852              :                -test_down, -response_test_down, qs_ot_env(1)%response_model_curvature, &
     853              :                qs_ot_env(1)%response_predicted_slope, qs_ot_env(1)%response_shadow_curvature, &
     854              :                qs_ot_env(1)%ds_min, baseline_model_drop, response_model_drop, &
     855           22 :                response_relative_gain, use_response_candidate)
     856              :          END IF
     857           22 :          IF (logger%iter_info%print_level >= high_print_level .AND. logger%para_env%is_source()) THEN
     858              :             WRITE (cp_logger_get_default_unit_nr(logger), '(A,4(1X,I5),5(1X,ES16.8),2(1X,L1))') &
     859              :                " OT Mermin response candidate comparison directions shadow active cooldown residual "// &
     860            0 :                "curvature baseline response gain probe use:", &
     861            0 :                qs_ot_env(1)%response_candidate_directions, &
     862            0 :                qs_ot_env(1)%response_shadow_good_samples, &
     863            0 :                qs_ot_env(1)%response_candidate_good_samples, &
     864            0 :                qs_ot_env(1)%response_candidate_cooldown, baseline_delta, &
     865            0 :                qs_ot_env(1)%response_model_curvature, baseline_model_drop, response_model_drop, &
     866            0 :                response_relative_gain, probe_response_candidate, use_response_candidate
     867              :          END IF
     868           22 :          IF (use_response_candidate) THEN
     869           40 :             DO ispin = 1, nspin
     870           24 :                IF (do_ks) THEN
     871           24 :                   CALL dbcsr_copy(qs_ot_env(ispin)%matrix_dx, qs_ot_env(ispin)%matrix_response_gx)
     872           24 :                   CALL dbcsr_scale(qs_ot_env(ispin)%matrix_dx, -1.0_dp)
     873           24 :                   IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
     874              :                      CALL dbcsr_copy(qs_ot_env(ispin)%matrix_dx_im, &
     875           24 :                                      qs_ot_env(ispin)%matrix_response_gx_im)
     876           24 :                      CALL dbcsr_scale(qs_ot_env(ispin)%matrix_dx_im, -1.0_dp)
     877              :                   END IF
     878              :                   CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_dx, &
     879           24 :                                   qs_ot_env(ispin)%rot_mat_response_gx)
     880           24 :                   CALL dbcsr_scale(qs_ot_env(ispin)%rot_mat_dx, -1.0_dp)
     881           24 :                   IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
     882              :                      CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_dx_im, &
     883           24 :                                      qs_ot_env(ispin)%rot_mat_response_gx_im)
     884           24 :                      CALL dbcsr_scale(qs_ot_env(ispin)%rot_mat_dx_im, -1.0_dp)
     885              :                   END IF
     886              :                END IF
     887          160 :                IF (do_ener) qs_ot_env(ispin)%ener_dx = -qs_ot_env(ispin)%ener_response_gx
     888              :             END DO
     889           16 :             test_down = response_test_down
     890              :          END IF
     891              :       END IF
     892              : 
     893        23682 :       qs_ot_env(1)%response_reference_energy = qs_ot_env(1)%etotal
     894        23682 :       qs_ot_env(1)%response_reference_residual = baseline_delta
     895        23682 :       IF (test_down < 0.0_dp) THEN
     896        23049 :          qs_ot_env(1)%response_predicted_slope = -test_down
     897              :       ELSE
     898          633 :          qs_ot_env(1)%response_predicted_slope = qs_ot_env(1)%gnorm
     899              :       END IF
     900        23682 :       IF (use_response_candidate) THEN
     901           16 :          qs_ot_env(1)%response_candidate_pending = .TRUE.
     902           16 :          qs_ot_env(1)%response_shadow_pending = .FALSE.
     903           16 :          qs_ot_env(1)%response_predicted_curvature = qs_ot_env(1)%response_model_curvature
     904              :       ELSE
     905        23666 :          qs_ot_env(1)%response_candidate_pending = .FALSE.
     906              :          qs_ot_env(1)%response_shadow_pending = candidate_available .AND. &
     907              :                                                 ot_mermin_response_shadow_followup( &
     908              :                                                 baseline_delta, &
     909              :                                                 qs_ot_env(1)%response_candidate_directions, &
     910              :                                                 qs_ot_env(1)%response_shadow_good_samples, &
     911              :                                                 qs_ot_env(1)%response_candidate_good_samples, &
     912        47202 :                                                 qs_ot_env(1)%response_candidate_cooldown)
     913              :       END IF
     914              : 
     915        23682 :    END SUBROUTINE ot_try_mermin_response_direction
     916              : 
     917              : !
     918              : ! checks if the current point is a good point for finding a new direction
     919              : ! or if we should improve the line_search, if it is used
     920              : !
     921              : ! **************************************************************************************************
     922              : !> \brief ...
     923              : !> \param qs_ot_env ...
     924              : !> \return ...
     925              : ! **************************************************************************************************
     926        46186 :    FUNCTION current_point_is_fine(qs_ot_env) RESULT(res)
     927              :       TYPE(qs_ot_type), DIMENSION(:), POINTER            :: qs_ot_env
     928              :       LOGICAL                                            :: res
     929              : 
     930        46186 :       res = .FALSE.
     931              : 
     932              :       ! only if we have a gradient it can be fine
     933        46186 :       IF (.NOT. qs_ot_env(1)%energy_only) THEN
     934              : 
     935              :          ! we have not yet started with the line search
     936        23746 :          IF (qs_ot_env(1)%line_search_count == 0) THEN
     937        46186 :             res = .TRUE.
     938              :             RETURN
     939              :          END IF
     940              : 
     941        20472 :          IF (qs_ot_env(1)%line_search_might_be_done) THEN
     942              :             ! here we put the more complicated logic later
     943        20472 :             res = .TRUE.
     944        20472 :             RETURN
     945              :          END IF
     946              : 
     947              :       END IF
     948              : 
     949              :    END FUNCTION current_point_is_fine
     950              : 
     951              : !
     952              : ! performs various kinds of line searches
     953              : !
     954              : ! **************************************************************************************************
     955              : !> \brief ...
     956              : !> \param qs_ot_env ...
     957              : ! **************************************************************************************************
     958        46186 :    SUBROUTINE do_line_search(qs_ot_env)
     959              :       TYPE(qs_ot_type), DIMENSION(:), POINTER            :: qs_ot_env
     960              : 
     961        46614 :       SELECT CASE (qs_ot_env(1)%settings%line_search_method)
     962              :       CASE ("GOLD")
     963          428 :          CALL do_line_search_gold(qs_ot_env)
     964              :       CASE ("3PNT")
     965         1608 :          CALL do_line_search_3pnt(qs_ot_env)
     966              :       CASE ("2PNT")
     967        42870 :          IF (use_three_point_mermin_search(qs_ot_env)) THEN
     968         1062 :             CALL do_line_search_3pnt(qs_ot_env)
     969              :          ELSE
     970        41808 :             CALL do_line_search_2pnt(qs_ot_env)
     971              :          END IF
     972              :       CASE ("ADPT")
     973         1270 :          CALL do_line_search_adapt(qs_ot_env)
     974              :       CASE ("NONE")
     975           10 :          CALL do_line_search_none(qs_ot_env)
     976              :       CASE DEFAULT
     977        46186 :          CPABORT("NYI")
     978              :       END SELECT
     979        46186 :    END SUBROUTINE do_line_search
     980              : 
     981              : ! **************************************************************************************************
     982              : !> \brief Add an energy-only guard point to strongly preconditioned complex Mermin steps.
     983              : !> \param qs_ot_env OT environments
     984              : !> \return Whether to use the guarded three-point search
     985              : ! **************************************************************************************************
     986        43734 :    FUNCTION use_three_point_mermin_search(qs_ot_env) RESULT(res)
     987              :       TYPE(qs_ot_type), DIMENSION(:), POINTER            :: qs_ot_env
     988              :       LOGICAL                                            :: res
     989              : 
     990              :       INTEGER                                            :: ispin
     991              : 
     992        43734 :       res = .FALSE.
     993        43734 :       IF (.NOT. qs_ot_env(1)%settings%occupation_preconditioner) RETURN
     994              : 
     995         1402 :       DO ispin = 1, SIZE(qs_ot_env)
     996         1402 :          IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
     997        43734 :             res = .TRUE.
     998              :             RETURN
     999              :          END IF
    1000              :       END DO
    1001              :    END FUNCTION use_three_point_mermin_search
    1002              : 
    1003              : ! **************************************************************************************************
    1004              : !> \brief moves x adding the right amount (ds) of the gradient or search direction
    1005              : !> \param ds ...
    1006              : !> \param qs_ot_env ...
    1007              : !> \par History
    1008              : !>      08.2004 created [ Joost VandeVondele ] copied here from a larger number of subroutines
    1009              : ! **************************************************************************************************
    1010        46186 :    SUBROUTINE take_step(ds, qs_ot_env)
    1011              :       REAL(KIND=dp)                                      :: ds
    1012              :       TYPE(qs_ot_type), DIMENSION(:), POINTER            :: qs_ot_env
    1013              : 
    1014              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'take_step'
    1015              : 
    1016              :       INTEGER                                            :: handle, ispin, nspin
    1017              :       LOGICAL                                            :: do_ener, do_ks
    1018              : 
    1019        46186 :       CALL timeset(routineN, handle)
    1020              : 
    1021        46186 :       nspin = SIZE(qs_ot_env)
    1022              : 
    1023        46186 :       do_ks = qs_ot_env(1)%settings%ks
    1024        46186 :       do_ener = qs_ot_env(1)%settings%do_ener
    1025              : 
    1026              :       ! now update x to take into account this new step
    1027              :       ! either dx or -gx is the direction to use
    1028        46186 :       IF (qs_ot_env(1)%use_dx) THEN
    1029        46098 :          IF (do_ks) THEN
    1030       102844 :             DO ispin = 1, nspin
    1031              :                CALL dbcsr_add(qs_ot_env(ispin)%matrix_x, qs_ot_env(ispin)%matrix_dx, &
    1032        56746 :                               alpha_scalar=1.0_dp, beta_scalar=ds)
    1033        56746 :                IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    1034              :                   CALL dbcsr_add(qs_ot_env(ispin)%matrix_x_im, qs_ot_env(ispin)%matrix_dx_im, &
    1035         3627 :                                  alpha_scalar=1.0_dp, beta_scalar=ds)
    1036              :                END IF
    1037       102844 :                IF (qs_ot_env(ispin)%settings%do_rotation) THEN
    1038              :                   CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_x, qs_ot_env(ispin)%rot_mat_dx, &
    1039         5715 :                                  alpha_scalar=1.0_dp, beta_scalar=ds)
    1040         5715 :                   IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    1041              :                      CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_x_im, qs_ot_env(ispin)%rot_mat_dx_im, &
    1042         2377 :                                     alpha_scalar=1.0_dp, beta_scalar=ds)
    1043              :                   END IF
    1044              :                END IF
    1045              :             END DO
    1046              :          END IF
    1047        46098 :          IF (do_ener) THEN
    1048         2890 :             DO ispin = 1, nspin
    1049        14574 :                qs_ot_env(ispin)%ener_x = qs_ot_env(ispin)%ener_x + ds*qs_ot_env(ispin)%ener_dx
    1050              :             END DO
    1051              :          END IF
    1052              :       ELSE
    1053           88 :          IF (do_ks) THEN
    1054          176 :             DO ispin = 1, nspin
    1055              :                CALL dbcsr_add(qs_ot_env(ispin)%matrix_x, qs_ot_env(ispin)%matrix_gx, &
    1056           88 :                               alpha_scalar=1.0_dp, beta_scalar=-ds)
    1057           88 :                IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    1058              :                   CALL dbcsr_add(qs_ot_env(ispin)%matrix_x_im, qs_ot_env(ispin)%matrix_gx_im, &
    1059            0 :                                  alpha_scalar=1.0_dp, beta_scalar=-ds)
    1060              :                END IF
    1061          176 :                IF (qs_ot_env(ispin)%settings%do_rotation) THEN
    1062              :                   CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_x, qs_ot_env(ispin)%rot_mat_gx, &
    1063            0 :                                  alpha_scalar=1.0_dp, beta_scalar=-ds)
    1064            0 :                   IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    1065              :                      CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_x_im, qs_ot_env(ispin)%rot_mat_gx_im, &
    1066            0 :                                     alpha_scalar=1.0_dp, beta_scalar=-ds)
    1067              :                   END IF
    1068              :                END IF
    1069              :             END DO
    1070              :          END IF
    1071           88 :          IF (do_ener) THEN
    1072            0 :             DO ispin = 1, nspin
    1073            0 :                qs_ot_env(ispin)%ener_x = qs_ot_env(ispin)%ener_x - ds*qs_ot_env(ispin)%ener_gx
    1074              :             END DO
    1075              :          END IF
    1076              :       END IF
    1077        46186 :       CALL timestop(handle)
    1078        46186 :    END SUBROUTINE take_step
    1079              : 
    1080              : ! implements a golden ratio search as a robust way of minimizing
    1081              : ! **************************************************************************************************
    1082              : !> \brief ...
    1083              : !> \param qs_ot_env ...
    1084              : ! **************************************************************************************************
    1085          428 :    SUBROUTINE do_line_search_gold(qs_ot_env)
    1086              : 
    1087              :       TYPE(qs_ot_type), DIMENSION(:), POINTER            :: qs_ot_env
    1088              : 
    1089              :       CHARACTER(len=*), PARAMETER :: routineN = 'do_line_search_gold'
    1090              :       REAL(KIND=dp), PARAMETER                           :: gold_sec = 0.3819_dp
    1091              : 
    1092              :       INTEGER                                            :: count, handle
    1093              :       REAL(KIND=dp)                                      :: ds
    1094              : 
    1095          428 :       CALL timeset(routineN, handle)
    1096              : 
    1097          428 :       qs_ot_env(1)%line_search_count = qs_ot_env(1)%line_search_count + 1
    1098          428 :       count = qs_ot_env(1)%line_search_count
    1099          428 :       qs_ot_env(1)%line_search_might_be_done = .FALSE.
    1100          428 :       qs_ot_env(1)%energy_only = .TRUE.
    1101              : 
    1102          428 :       IF (count + 1 > SIZE(qs_ot_env(1)%OT_pos)) THEN
    1103              :          ! should not happen, we pass with a warning first
    1104              :          ! you can increase the size of OT_pos and the like in qs_ot_env
    1105            0 :          CPABORT("MAX ITER EXCEEDED : FATAL")
    1106              :       END IF
    1107              : 
    1108          428 :       IF (qs_ot_env(1)%line_search_count == 1) THEN
    1109           54 :          qs_ot_env(1)%line_search_left = 1
    1110           54 :          qs_ot_env(1)%line_search_right = 0
    1111           54 :          qs_ot_env(1)%line_search_mid = 1
    1112           54 :          qs_ot_env(1)%ot_pos(1) = 0.0_dp
    1113           54 :          qs_ot_env(1)%ot_energy(1) = qs_ot_env(1)%etotal
    1114           54 :          qs_ot_env(1)%ot_pos(2) = qs_ot_env(1)%ds_min/gold_sec
    1115              :       ELSE
    1116          374 :          qs_ot_env(1)%ot_energy(count) = qs_ot_env(1)%etotal
    1117              :          ! it's essentially a book keeping game.
    1118              :          ! keep left on the left, keep (bring) right on the right
    1119              :          ! and mid in between these two
    1120          374 :          IF (qs_ot_env(1)%line_search_right == 0) THEN ! we do not yet have the right bracket
    1121           64 :             IF (qs_ot_env(1)%ot_energy(count - 1) < qs_ot_env(1)%ot_energy(count)) THEN
    1122           42 :                qs_ot_env(1)%line_search_right = count
    1123              :                qs_ot_env(1)%ot_pos(count + 1) = qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_mid) + &
    1124              :                                                 (qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_right) - &
    1125           42 :                                                  qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_mid))*gold_sec
    1126              :             ELSE
    1127           22 :                qs_ot_env(1)%line_search_left = qs_ot_env(1)%line_search_mid
    1128           22 :                qs_ot_env(1)%line_search_mid = count
    1129           22 :                qs_ot_env(1)%ot_pos(count + 1) = qs_ot_env(1)%ot_pos(count)/gold_sec ! expand
    1130              :             END IF
    1131              :          ELSE
    1132              :             ! first determine where we are and construct the new triplet
    1133          310 :             IF (qs_ot_env(1)%ot_pos(count) < qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_mid)) THEN
    1134          126 :                IF (qs_ot_env(1)%ot_energy(count) < qs_ot_env(1)%ot_energy(qs_ot_env(1)%line_search_mid)) THEN
    1135           42 :                   qs_ot_env(1)%line_search_right = qs_ot_env(1)%line_search_mid
    1136           42 :                   qs_ot_env(1)%line_search_mid = count
    1137              :                ELSE
    1138           84 :                   qs_ot_env(1)%line_search_left = count
    1139              :                END IF
    1140              :             ELSE
    1141          184 :                IF (qs_ot_env(1)%ot_energy(count) < qs_ot_env(1)%ot_energy(qs_ot_env(1)%line_search_mid)) THEN
    1142           76 :                   qs_ot_env(1)%line_search_left = qs_ot_env(1)%line_search_mid
    1143           76 :                   qs_ot_env(1)%line_search_mid = count
    1144              :                ELSE
    1145          108 :                   qs_ot_env(1)%line_search_right = count
    1146              :                END IF
    1147              :             END IF
    1148              :             ! now find the new point in the largest section
    1149          310 :             IF ((qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_right) &
    1150              :                  - qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_mid)) > &
    1151              :                 (qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_mid) &
    1152              :                  - qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_left))) THEN
    1153              :                qs_ot_env(1)%ot_pos(count + 1) = &
    1154              :                   qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_mid) + &
    1155              :                   gold_sec*(qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_right) &
    1156          162 :                             - qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_mid))
    1157              :             ELSE
    1158              :                qs_ot_env(1)%ot_pos(count + 1) = &
    1159              :                   qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_left) + &
    1160              :                   gold_sec*(qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_mid) &
    1161          148 :                             - qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_left))
    1162              :             END IF
    1163              :             ! check for termination
    1164              :             IF (((qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_right) &
    1165              :                   - qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_mid)) < &
    1166          310 :                  qs_ot_env(1)%ds_min*qs_ot_env(1)%settings%gold_target) .AND. &
    1167              :                 ((qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_mid) &
    1168              :                   - qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_left)) < &
    1169              :                  qs_ot_env(1)%ds_min*qs_ot_env(1)%settings%gold_target)) THEN
    1170           42 :                qs_ot_env(1)%energy_only = .FALSE.
    1171           42 :                qs_ot_env(1)%line_search_might_be_done = .TRUE.
    1172              :             END IF
    1173              :          END IF
    1174              :       END IF
    1175          428 :       ds = qs_ot_env(1)%OT_pos(count + 1) - qs_ot_env(1)%OT_pos(count)
    1176          428 :       qs_ot_env(1)%ds_min = qs_ot_env(1)%OT_pos(count + 1)
    1177              : 
    1178          428 :       CALL take_step(ds, qs_ot_env)
    1179              : 
    1180          428 :       CALL timestop(handle)
    1181              : 
    1182          428 :    END SUBROUTINE do_line_search_gold
    1183              : 
    1184              : ! **************************************************************************************************
    1185              : !> \brief ...
    1186              : !> \param qs_ot_env ...
    1187              : ! **************************************************************************************************
    1188         2670 :    SUBROUTINE do_line_search_3pnt(qs_ot_env)
    1189              : 
    1190              :       TYPE(qs_ot_type), DIMENSION(:), POINTER            :: qs_ot_env
    1191              : 
    1192              :       CHARACTER(len=*), PARAMETER :: routineN = 'do_line_search_3pnt'
    1193              : 
    1194              :       INTEGER                                            :: best_index, count, handle, i
    1195              :       REAL(KIND=dp)                                      :: best_energy, denom, ds, fa, fb, fc, nom, &
    1196              :                                                             pos, tol, val, xa, xb, xc
    1197              : 
    1198         2670 :       CALL timeset(routineN, handle)
    1199              : 
    1200         2670 :       qs_ot_env(1)%line_search_might_be_done = .FALSE.
    1201         2670 :       qs_ot_env(1)%energy_only = .TRUE.
    1202              : 
    1203              :       ! a three point interpolation based on the energy
    1204         2670 :       qs_ot_env(1)%line_search_count = qs_ot_env(1)%line_search_count + 1
    1205         2670 :       count = qs_ot_env(1)%line_search_count
    1206         2670 :       qs_ot_env(1)%ot_energy(count) = qs_ot_env(1)%etotal
    1207          942 :       SELECT CASE (count)
    1208              :       CASE (1)
    1209          942 :          qs_ot_env(1)%ot_pos(count) = 0.0_dp
    1210          942 :          qs_ot_env(1)%ot_pos(count + 1) = qs_ot_env(1)%ds_min*0.8_dp
    1211              :       CASE (2)
    1212          864 :          IF (qs_ot_env(1)%OT_energy(count) > qs_ot_env(1)%OT_energy(count - 1)) THEN
    1213          102 :             qs_ot_env(1)%OT_pos(count + 1) = qs_ot_env(1)%ds_min*0.5_dp
    1214              :          ELSE
    1215          762 :             qs_ot_env(1)%OT_pos(count + 1) = qs_ot_env(1)%ds_min*1.4_dp
    1216              :          END IF
    1217              :       CASE (3)
    1218          864 :          xa = qs_ot_env(1)%OT_pos(1)
    1219          864 :          xb = qs_ot_env(1)%OT_pos(2)
    1220          864 :          xc = qs_ot_env(1)%OT_pos(3)
    1221          864 :          fa = qs_ot_env(1)%OT_energy(1)
    1222          864 :          fb = qs_ot_env(1)%OT_energy(2)
    1223          864 :          fc = qs_ot_env(1)%OT_energy(3)
    1224          864 :          nom = (xb - xa)**2*(fb - fc) - (xb - xc)**2*(fb - fa)
    1225          864 :          denom = (xb - xa)*(fb - fc) - (xb - xc)*(fb - fa)
    1226          864 :          IF (ABS(denom) <= 1.0E-18_dp*MAX(ABS(fb - fc), ABS(fb - fa))) THEN
    1227              :             pos = xb
    1228              :          ELSE
    1229          864 :             pos = xb - 0.5_dp*nom/denom ! position of the stationary point
    1230              :          END IF
    1231              :          val = (pos - xa)*(pos - xb)*fc/((xc - xa)*(xc - xb)) + &
    1232              :                (pos - xb)*(pos - xc)*fa/((xa - xb)*(xa - xc)) + &
    1233          864 :                (pos - xc)*(pos - xa)*fb/((xb - xc)*(xb - xa))
    1234          864 :          best_index = 1
    1235         2592 :          DO i = 2, count
    1236         2592 :             IF (qs_ot_env(1)%OT_energy(i) < qs_ot_env(1)%OT_energy(best_index)) best_index = i
    1237              :          END DO
    1238          864 :          best_energy = qs_ot_env(1)%OT_energy(best_index)
    1239          864 :          tol = 10.0_dp*EPSILON(1.0_dp)*MAX(1.0_dp, ABS(best_energy))
    1240          864 :          IF (use_three_point_mermin_search(qs_ot_env) .AND. best_index /= 1 .AND. &
    1241              :              val >= best_energy - tol) THEN
    1242           10 :             qs_ot_env(1)%OT_pos(count + 1) = qs_ot_env(1)%OT_pos(best_index)
    1243          854 :          ELSE IF (val < fa .AND. val <= fb .AND. val <= fc) THEN ! OK, we go to a minimum
    1244              :             ! we take a guard against too large steps
    1245              :             qs_ot_env(1)%OT_pos(count + 1) = MAX(MAXVAL(qs_ot_env(1)%OT_pos(1:3))*0.01_dp, &
    1246         3408 :                                                  MIN(pos, MAXVAL(qs_ot_env(1)%OT_pos(1:3))*4.0_dp))
    1247              :          ELSE ! just take an extended step
    1248            8 :             qs_ot_env(1)%OT_pos(count + 1) = MAXVAL(qs_ot_env(1)%OT_pos(1:3))*2.0_dp
    1249              :          END IF
    1250          864 :          qs_ot_env(1)%energy_only = .FALSE.
    1251          864 :          qs_ot_env(1)%line_search_might_be_done = .TRUE.
    1252              :       CASE DEFAULT
    1253         2670 :          CPABORT("NYI")
    1254              :       END SELECT
    1255         2670 :       ds = qs_ot_env(1)%OT_pos(count + 1) - qs_ot_env(1)%OT_pos(count)
    1256         2670 :       qs_ot_env(1)%ds_min = qs_ot_env(1)%OT_pos(count + 1)
    1257              : 
    1258         2670 :       CALL take_step(ds, qs_ot_env)
    1259              : 
    1260         2670 :       CALL timestop(handle)
    1261              : 
    1262         2670 :    END SUBROUTINE do_line_search_3pnt
    1263              : 
    1264              : ! **************************************************************************************************
    1265              : !> \brief ...
    1266              : !> \param qs_ot_env ...
    1267              : ! **************************************************************************************************
    1268        41808 :    SUBROUTINE do_line_search_2pnt(qs_ot_env)
    1269              : 
    1270              :       TYPE(qs_ot_type), DIMENSION(:), POINTER            :: qs_ot_env
    1271              : 
    1272              :       CHARACTER(len=*), PARAMETER :: routineN = 'do_line_search_2pnt'
    1273              : 
    1274              :       INTEGER                                            :: count, handle
    1275              :       REAL(KIND=dp)                                      :: a, b, c, ds, pos, val, x0, x1
    1276              : 
    1277        41808 :       CALL timeset(routineN, handle)
    1278              : 
    1279        41808 :       qs_ot_env(1)%line_search_might_be_done = .FALSE.
    1280        41808 :       qs_ot_env(1)%energy_only = .TRUE.
    1281              : 
    1282              :       ! a three point interpolation based on the energy
    1283        41808 :       qs_ot_env(1)%line_search_count = qs_ot_env(1)%line_search_count + 1
    1284        41808 :       count = qs_ot_env(1)%line_search_count
    1285        41808 :       qs_ot_env(1)%ot_energy(count) = qs_ot_env(1)%etotal
    1286        22370 :       SELECT CASE (count)
    1287              :       CASE (1)
    1288        22370 :          qs_ot_env(1)%ot_pos(count) = 0.0_dp
    1289        22370 :          qs_ot_env(1)%ot_grad(count) = qs_ot_env(1)%gradient
    1290        22370 :          qs_ot_env(1)%ot_pos(count + 1) = qs_ot_env(1)%ds_min*1.0_dp
    1291              :       CASE (2)
    1292        19438 :          x0 = 0.0_dp
    1293        19438 :          c = qs_ot_env(1)%ot_energy(1)
    1294        19438 :          b = qs_ot_env(1)%ot_grad(1)
    1295        19438 :          x1 = qs_ot_env(1)%ot_pos(2)
    1296        19438 :          a = (qs_ot_env(1)%ot_energy(2) - b*x1 - c)/(x1**2)
    1297        19438 :          IF (a <= 0.0_dp) a = 1.0E-15_dp
    1298        19438 :          pos = -b/(2.0_dp*a)
    1299        19438 :          val = a*pos**2 + b*pos + c
    1300        19438 :          qs_ot_env(1)%energy_only = .FALSE.
    1301        19438 :          qs_ot_env(1)%line_search_might_be_done = .TRUE.
    1302        19438 :          IF (val < qs_ot_env(1)%ot_energy(1) .AND. val <= qs_ot_env(1)%ot_energy(2)) THEN
    1303              :             ! we go to a minimum, but ...
    1304              :             ! we take a guard against too large steps
    1305              :             qs_ot_env(1)%OT_pos(count + 1) = MAX(MAXVAL(qs_ot_env(1)%OT_pos(1:2))*0.01_dp, &
    1306        58074 :                                                  MIN(pos, MAXVAL(qs_ot_env(1)%OT_pos(1:2))*4.0_dp))
    1307              :          ELSE ! just take an extended step
    1308          240 :             qs_ot_env(1)%OT_pos(count + 1) = MAXVAL(qs_ot_env(1)%OT_pos(1:2))*2.0_dp
    1309              :          END IF
    1310              :       CASE DEFAULT
    1311        41808 :          CPABORT("NYI")
    1312              :       END SELECT
    1313        41808 :       ds = qs_ot_env(1)%OT_pos(count + 1) - qs_ot_env(1)%OT_pos(count)
    1314        41808 :       qs_ot_env(1)%ds_min = qs_ot_env(1)%OT_pos(count + 1)
    1315              : 
    1316        41808 :       CALL take_step(ds, qs_ot_env)
    1317              : 
    1318        41808 :       CALL timestop(handle)
    1319              : 
    1320        41808 :    END SUBROUTINE do_line_search_2pnt
    1321              : 
    1322              : ! **************************************************************************************************
    1323              : !> \brief ...
    1324              : !> \param qs_ot_env ...
    1325              : ! **************************************************************************************************
    1326         1270 :    SUBROUTINE do_line_search_adapt(qs_ot_env)
    1327              : 
    1328              :       TYPE(qs_ot_type), DIMENSION(:), POINTER            :: qs_ot_env
    1329              : 
    1330              :       CHARACTER(len=*), PARAMETER :: routineN = 'do_line_search_adapt'
    1331              :       REAL(KIND=dp), PARAMETER                           :: grow_factor = 2.0_dp, &
    1332              :                                                             shrink_factor = 0.5_dp
    1333              : 
    1334              :       INTEGER                                            :: count, handle, il, im, ir
    1335              :       REAL(KIND=dp)                                      :: a, b, c, denom, ds, el, em, er, &
    1336              :                                                             step_size, xl, xm, xr
    1337              : 
    1338         1270 :       CALL timeset(routineN, handle)
    1339              : 
    1340         1270 :       qs_ot_env(1)%line_search_count = qs_ot_env(1)%line_search_count + 1
    1341         1270 :       count = qs_ot_env(1)%line_search_count
    1342         1270 :       qs_ot_env(1)%line_search_might_be_done = .FALSE.
    1343         1270 :       qs_ot_env(1)%energy_only = .TRUE.
    1344              : 
    1345         1270 :       IF (count + 1 > SIZE(qs_ot_env(1)%OT_pos)) THEN
    1346              :          ! should not happen, we pass with a warning first
    1347              :          ! you can increase the size of OT_pos and the like in qs_ot_env
    1348            0 :          CPABORT("MAX ITER EXCEEDED : FATAL")
    1349              :       END IF
    1350              : 
    1351              :       ! Perform an adaptive linesearch
    1352         1270 :       IF (qs_ot_env(1)%line_search_count == 1) THEN
    1353          370 :          qs_ot_env(1)%line_search_left = 1
    1354          370 :          qs_ot_env(1)%line_search_right = 0
    1355          370 :          qs_ot_env(1)%line_search_mid = 1
    1356          370 :          qs_ot_env(1)%ot_Pos(1) = 0.0_dp
    1357          370 :          qs_ot_env(1)%ot_energy(1) = qs_ot_env(1)%etotal
    1358          370 :          qs_ot_env(1)%ot_Pos(2) = qs_ot_env(1)%ds_min*grow_factor
    1359              :       ELSE
    1360          900 :          qs_ot_env(1)%ot_energy(count) = qs_ot_env(1)%etotal
    1361              :          ! it's essentially a book keeping game.
    1362              :          ! keep left on the left, keep (bring) right on the right
    1363              :          ! and mid in between these two
    1364          900 :          IF (qs_ot_env(1)%line_search_right == 0) THEN ! we do not yet have the right bracket
    1365          536 :             IF (qs_ot_env(1)%ot_energy(count - 1) < qs_ot_env(1)%ot_energy(count)) THEN
    1366          338 :                qs_ot_env(1)%line_search_right = count
    1367              :                qs_ot_env(1)%ot_Pos(count + 1) = qs_ot_env(1)%ot_Pos(qs_ot_env(1)%line_search_mid) + &
    1368              :                                                 (qs_ot_env(1)%ot_Pos(qs_ot_env(1)%line_search_right) - &
    1369          338 :                                                  qs_ot_env(1)%ot_Pos(qs_ot_env(1)%line_search_mid))*shrink_factor
    1370              :             ELSE
    1371              :                ! expand further
    1372          198 :                qs_ot_env(1)%line_search_left = qs_ot_env(1)%line_search_mid
    1373          198 :                qs_ot_env(1)%line_search_mid = count
    1374          198 :                qs_ot_env(1)%ot_Pos(count + 1) = qs_ot_env(1)%ot_Pos(count)*grow_factor
    1375              :             END IF
    1376              :          ELSE
    1377              :             ! first determine where we are and construct the new triplet
    1378          364 :             IF (qs_ot_env(1)%ot_pos(count) < qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_mid)) THEN
    1379            0 :                IF (qs_ot_env(1)%ot_energy(count) < qs_ot_env(1)%ot_energy(qs_ot_env(1)%line_search_mid)) THEN
    1380            0 :                   qs_ot_env(1)%line_search_right = qs_ot_env(1)%line_search_mid
    1381            0 :                   qs_ot_env(1)%line_search_mid = count
    1382              :                ELSE
    1383            0 :                   qs_ot_env(1)%line_search_left = count
    1384              :                END IF
    1385              :             ELSE
    1386          364 :                IF (qs_ot_env(1)%ot_energy(count) < qs_ot_env(1)%ot_energy(qs_ot_env(1)%line_search_mid)) THEN
    1387          160 :                   qs_ot_env(1)%line_search_left = qs_ot_env(1)%line_search_mid
    1388          160 :                   qs_ot_env(1)%line_search_mid = count
    1389              :                ELSE
    1390          204 :                   qs_ot_env(1)%line_search_right = count
    1391              :                END IF
    1392              :             END IF
    1393          364 :             il = qs_ot_env(1)%line_search_left
    1394          364 :             im = qs_ot_env(1)%line_search_mid
    1395          364 :             ir = qs_ot_env(1)%line_search_right
    1396          364 :             xl = qs_ot_env(1)%OT_pos(il)
    1397          364 :             xm = qs_ot_env(1)%OT_pos(im)
    1398          364 :             xr = qs_ot_env(1)%OT_pos(ir)
    1399          364 :             el = qs_ot_env(1)%ot_energy(il)
    1400          364 :             em = qs_ot_env(1)%ot_energy(im)
    1401          364 :             er = qs_ot_env(1)%ot_energy(ir)
    1402          364 :             IF (em < el) THEN
    1403          338 :                IF (er < em) THEN
    1404              :                   !extend search
    1405            0 :                   qs_ot_env(1)%ot_Pos(count + 1) = qs_ot_env(1)%ot_Pos(ir)*grow_factor
    1406              :                ELSE
    1407              :                   ! Cramer's rule
    1408          338 :                   denom = (xl - xm)*(xl - xr)*(xm - xr)
    1409          338 :                   a = (xr*(em - el) + xm*(el - er) + xl*(er - em))/denom
    1410          338 :                   b = (xr**2*(el - em) + xm**2*(er - el) + xl**2*(em - er))/denom
    1411          338 :                   c = (xm*xr*(xm - xr)*el + xr*xl*(xr - xl)*em + xr*xm*(xr - xm)*er)/denom
    1412              : 
    1413          338 :                   IF (ABS(a) /= 0.0_dp) THEN
    1414          338 :                      step_size = -b/(2.0_dp*a)
    1415              :                   ELSE
    1416              :                      step_size = 0.0_dp
    1417              :                   END IF
    1418          338 :                   CPASSERT(step_size >= 0.0_dp)
    1419          338 :                   qs_ot_env(1)%ot_Pos(count + 1) = step_size
    1420          338 :                   qs_ot_env(1)%line_search_might_be_done = .TRUE.
    1421          338 :                   qs_ot_env(1)%energy_only = .FALSE.
    1422              :                END IF
    1423              :             ELSE
    1424              :                ! contract search
    1425              :                qs_ot_env(1)%ot_Pos(count + 1) = qs_ot_env(1)%ot_Pos(im) + &
    1426           26 :                                                 (qs_ot_env(1)%ot_Pos(ir) - qs_ot_env(1)%ot_Pos(im))*shrink_factor
    1427              :             END IF
    1428              : 
    1429              :          END IF
    1430              :       END IF
    1431         1270 :       ds = qs_ot_env(1)%OT_pos(count + 1) - qs_ot_env(1)%OT_pos(count)
    1432         1270 :       qs_ot_env(1)%ds_min = qs_ot_env(1)%OT_pos(count + 1)
    1433              : 
    1434         1270 :       CALL take_step(ds, qs_ot_env)
    1435              : 
    1436         1270 :       CALL timestop(handle)
    1437              : 
    1438         1270 :    END SUBROUTINE do_line_search_adapt
    1439              : 
    1440              : ! **************************************************************************************************
    1441              : !> \brief ...
    1442              : !> \param qs_ot_env ...
    1443              : ! **************************************************************************************************
    1444           10 :    SUBROUTINE do_line_search_none(qs_ot_env)
    1445              :       TYPE(qs_ot_type), DIMENSION(:), POINTER            :: qs_ot_env
    1446              : 
    1447           10 :       CALL take_step(qs_ot_env(1)%ds_min, qs_ot_env)
    1448              : 
    1449           10 :    END SUBROUTINE do_line_search_none
    1450              : 
    1451              : !
    1452              : ! creates a new SD direction, using the preconditioner if associated
    1453              : ! also updates the gradient for line search
    1454              : !
    1455              : 
    1456              : ! **************************************************************************************************
    1457              : !> \brief ...
    1458              : !> \param qs_ot_env ...
    1459              : !> \param para_env_inter_kp communicator between distributed k-point groups
    1460              : ! **************************************************************************************************
    1461           64 :    SUBROUTINE ot_new_sd_direction(qs_ot_env, para_env_inter_kp)
    1462              :       TYPE(qs_ot_type), DIMENSION(:), POINTER            :: qs_ot_env
    1463              :       TYPE(mp_para_env_type), OPTIONAL, POINTER          :: para_env_inter_kp
    1464              : 
    1465              :       CHARACTER(len=*), PARAMETER :: routineN = 'ot_new_sd_direction'
    1466              : 
    1467              :       INTEGER                                            :: handle, ispin, itmp, k, n, nener, nspin
    1468              :       LOGICAL                                            :: do_ener, do_ks
    1469              :       REAL(KIND=dp)                                      :: channel_gnorm, nvariables, tmp
    1470              :       TYPE(cp_logger_type), POINTER                      :: logger
    1471              : 
    1472           64 :       CALL timeset(routineN, handle)
    1473              : 
    1474              : !***SCP
    1475              : 
    1476           64 :       nspin = SIZE(qs_ot_env)
    1477           64 :       logger => cp_get_default_logger()
    1478           64 :       do_ks = qs_ot_env(1)%settings%ks
    1479           64 :       do_ener = qs_ot_env(1)%settings%do_ener
    1480              : 
    1481           64 :       IF (ASSOCIATED(qs_ot_env(1)%preconditioner)) THEN
    1482           52 :          IF (.NOT. qs_ot_env(1)%use_dx) CPABORT("use dx")
    1483           52 :          qs_ot_env(1)%gnorm = 0.0_dp
    1484           52 :          IF (do_ks) THEN
    1485          130 :             DO ispin = 1, nspin
    1486           78 :                IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    1487           52 :                   IF (qs_ot_env(ispin)%settings%occupation_preconditioner) THEN
    1488              :                      CALL apply_preconditioner(qs_ot_env(ispin)%preconditioner, &
    1489              :                                                qs_ot_env(ispin)%matrix_preconditioned_gx, &
    1490              :                                                qs_ot_env(ispin)%matrix_preconditioned_gx_im, &
    1491              :                                                qs_ot_env(ispin)%matrix_dx, &
    1492           52 :                                                qs_ot_env(ispin)%matrix_dx_im)
    1493              :                   ELSE
    1494              :                      CALL apply_preconditioner(qs_ot_env(ispin)%preconditioner, &
    1495              :                                                qs_ot_env(ispin)%matrix_gx, &
    1496              :                                                qs_ot_env(ispin)%matrix_gx_im, &
    1497              :                                                qs_ot_env(ispin)%matrix_dx, &
    1498            0 :                                                qs_ot_env(ispin)%matrix_dx_im)
    1499              :                   END IF
    1500           52 :                   CPASSERT(qs_ot_env(ispin)%kpoint_weight > 0.0_dp)
    1501              :                   CALL dbcsr_scale(qs_ot_env(ispin)%matrix_dx, &
    1502           52 :                                    qs_ot_kpoint_preconditioner_scale(qs_ot_env(ispin)%kpoint_weight))
    1503              :                   CALL dbcsr_scale(qs_ot_env(ispin)%matrix_dx_im, &
    1504           52 :                                    qs_ot_kpoint_preconditioner_scale(qs_ot_env(ispin)%kpoint_weight))
    1505              :                ELSE
    1506           26 :                   IF (qs_ot_env(ispin)%settings%occupation_preconditioner) THEN
    1507              :                      CALL apply_preconditioner(qs_ot_env(ispin)%preconditioner, &
    1508              :                                                qs_ot_env(ispin)%matrix_preconditioned_gx, &
    1509            0 :                                                qs_ot_env(ispin)%matrix_dx)
    1510              :                   ELSE
    1511              :                      CALL apply_preconditioner(qs_ot_env(ispin)%preconditioner, &
    1512           26 :                                                qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_dx)
    1513              :                   END IF
    1514              :                END IF
    1515           78 :                channel_gnorm = 0.0_dp
    1516           78 :                CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_dx, tmp)
    1517           78 :                channel_gnorm = channel_gnorm + tmp
    1518           78 :                IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    1519           52 :                   CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx_im, qs_ot_env(ispin)%matrix_dx_im, tmp)
    1520           52 :                   channel_gnorm = channel_gnorm + tmp
    1521              :                END IF
    1522           78 :                IF (qs_ot_env(ispin)%settings%occupation_preconditioner .AND. &
    1523              :                    channel_gnorm <= 0.0_dp) THEN
    1524           28 :                   IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    1525              :                      CALL apply_preconditioner(qs_ot_env(ispin)%preconditioner, &
    1526              :                                                qs_ot_env(ispin)%matrix_gx, &
    1527              :                                                qs_ot_env(ispin)%matrix_gx_im, &
    1528              :                                                qs_ot_env(ispin)%matrix_dx, &
    1529           28 :                                                qs_ot_env(ispin)%matrix_dx_im)
    1530              :                      CALL dbcsr_scale(qs_ot_env(ispin)%matrix_dx, &
    1531           28 :                                       qs_ot_kpoint_preconditioner_scale(qs_ot_env(ispin)%kpoint_weight))
    1532              :                      CALL dbcsr_scale(qs_ot_env(ispin)%matrix_dx_im, &
    1533           28 :                                       qs_ot_kpoint_preconditioner_scale(qs_ot_env(ispin)%kpoint_weight))
    1534              :                   ELSE
    1535              :                      CALL apply_preconditioner(qs_ot_env(ispin)%preconditioner, &
    1536              :                                                qs_ot_env(ispin)%matrix_gx, &
    1537            0 :                                                qs_ot_env(ispin)%matrix_dx)
    1538              :                   END IF
    1539           28 :                   channel_gnorm = 0.0_dp
    1540           28 :                   CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_dx, tmp)
    1541           28 :                   channel_gnorm = channel_gnorm + tmp
    1542           28 :                   IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    1543              :                      CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx_im, &
    1544           28 :                                     qs_ot_env(ispin)%matrix_dx_im, tmp)
    1545           28 :                      channel_gnorm = channel_gnorm + tmp
    1546              :                   END IF
    1547              :                END IF
    1548          208 :                qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + channel_gnorm
    1549              :             END DO
    1550           52 :             IF (qs_ot_env(1)%gnorm < 0.0_dp) THEN
    1551            0 :                logger => cp_get_default_logger()
    1552            0 :                WRITE (cp_logger_get_default_unit_nr(logger), *) "WARNING Preconditioner not positive definite !"
    1553              :             END IF
    1554          130 :             DO ispin = 1, nspin
    1555           78 :                CALL dbcsr_scale(qs_ot_env(ispin)%matrix_dx, -1.0_dp)
    1556          130 :                IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    1557           52 :                   CALL dbcsr_scale(qs_ot_env(ispin)%matrix_dx_im, -1.0_dp)
    1558              :                END IF
    1559              :             END DO
    1560           52 :             IF (qs_ot_env(1)%settings%do_rotation) THEN
    1561           78 :                DO ispin = 1, nspin
    1562              :                   ! right now no preconditioner yet
    1563           52 :                   CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_dx, qs_ot_env(ispin)%rot_mat_gx)
    1564           52 :                   CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx, qs_ot_env(ispin)%rot_mat_dx, tmp)
    1565              :                   ! added 0.5, because we have (antisymmetry) only half the number of variables
    1566           52 :                   qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + 0.5_dp*tmp
    1567           78 :                   IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    1568           52 :                      CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_dx_im, qs_ot_env(ispin)%rot_mat_gx_im)
    1569              :                      CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx_im, &
    1570           52 :                                     qs_ot_env(ispin)%rot_mat_dx_im, tmp)
    1571           52 :                      qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + 0.5_dp*tmp
    1572              :                   END IF
    1573              :                END DO
    1574           78 :                DO ispin = 1, nspin
    1575           52 :                   CALL dbcsr_scale(qs_ot_env(ispin)%rot_mat_dx, -1.0_dp)
    1576           78 :                   IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    1577           52 :                      CALL dbcsr_scale(qs_ot_env(ispin)%rot_mat_dx_im, -1.0_dp)
    1578              :                   END IF
    1579              :                END DO
    1580              :             END IF
    1581              :          END IF
    1582           52 :          IF (do_ener) THEN
    1583           78 :             DO ispin = 1, nspin
    1584           52 :                IF (qs_ot_env(ispin)%settings%occupation_preconditioner) THEN
    1585          156 :                   qs_ot_env(ispin)%ener_dx = qs_ot_env(ispin)%ener_preconditioned_gx
    1586              :                ELSE
    1587            0 :                   qs_ot_env(ispin)%ener_dx = qs_ot_env(ispin)%ener_gx
    1588              :                END IF
    1589          156 :                tmp = DOT_PRODUCT(qs_ot_env(ispin)%ener_dx, qs_ot_env(ispin)%ener_gx)
    1590           52 :                IF (qs_ot_env(ispin)%settings%occupation_preconditioner .AND. tmp <= 0.0_dp) THEN
    1591           96 :                   qs_ot_env(ispin)%ener_dx = qs_ot_env(ispin)%ener_gx
    1592           96 :                   tmp = DOT_PRODUCT(qs_ot_env(ispin)%ener_gx, qs_ot_env(ispin)%ener_gx)
    1593              :                END IF
    1594           52 :                qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
    1595          182 :                qs_ot_env(ispin)%ener_dx = -qs_ot_env(ispin)%ener_dx
    1596              :             END DO
    1597              :          END IF
    1598              :       ELSE
    1599           12 :          qs_ot_env(1)%gnorm = 0.0_dp
    1600           12 :          IF (do_ks) THEN
    1601           24 :             DO ispin = 1, nspin
    1602           12 :                channel_gnorm = 0.0_dp
    1603           12 :                IF (qs_ot_env(ispin)%settings%occupation_preconditioner) THEN
    1604              :                   CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, &
    1605            0 :                                  qs_ot_env(ispin)%matrix_preconditioned_gx, tmp)
    1606              :                ELSE
    1607           12 :                   CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_gx, tmp)
    1608              :                END IF
    1609           12 :                channel_gnorm = channel_gnorm + tmp
    1610           12 :                IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    1611            0 :                   IF (qs_ot_env(ispin)%settings%occupation_preconditioner) THEN
    1612              :                      CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx_im, &
    1613            0 :                                     qs_ot_env(ispin)%matrix_preconditioned_gx_im, tmp)
    1614              :                   ELSE
    1615            0 :                      CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx_im, qs_ot_env(ispin)%matrix_gx_im, tmp)
    1616              :                   END IF
    1617            0 :                   channel_gnorm = channel_gnorm + tmp
    1618              :                END IF
    1619           12 :                IF (qs_ot_env(ispin)%settings%occupation_preconditioner) THEN
    1620            0 :                   IF (channel_gnorm <= 0.0_dp) THEN
    1621              :                      CALL dbcsr_copy(qs_ot_env(ispin)%matrix_preconditioned_gx, &
    1622            0 :                                      qs_ot_env(ispin)%matrix_gx)
    1623            0 :                      IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    1624              :                         CALL dbcsr_copy(qs_ot_env(ispin)%matrix_preconditioned_gx_im, &
    1625            0 :                                         qs_ot_env(ispin)%matrix_gx_im)
    1626              :                      END IF
    1627            0 :                      channel_gnorm = 0.0_dp
    1628              :                      CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, &
    1629            0 :                                     qs_ot_env(ispin)%matrix_preconditioned_gx, tmp)
    1630            0 :                      channel_gnorm = channel_gnorm + tmp
    1631            0 :                      IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    1632              :                         CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx_im, &
    1633            0 :                                        qs_ot_env(ispin)%matrix_preconditioned_gx_im, tmp)
    1634            0 :                         channel_gnorm = channel_gnorm + tmp
    1635              :                      END IF
    1636              :                   END IF
    1637              :                   CALL dbcsr_copy(qs_ot_env(ispin)%matrix_gx, &
    1638            0 :                                   qs_ot_env(ispin)%matrix_preconditioned_gx)
    1639            0 :                   IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    1640              :                      CALL dbcsr_copy(qs_ot_env(ispin)%matrix_gx_im, &
    1641            0 :                                      qs_ot_env(ispin)%matrix_preconditioned_gx_im)
    1642              :                   END IF
    1643              :                END IF
    1644           24 :                qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + channel_gnorm
    1645              :             END DO
    1646           12 :             IF (qs_ot_env(1)%settings%do_rotation) THEN
    1647            0 :                DO ispin = 1, nspin
    1648            0 :                   CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx, qs_ot_env(ispin)%rot_mat_gx, tmp)
    1649              :                   ! added 0.5, because we have (antisymmetry) only half the number of variables
    1650            0 :                   qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + 0.5_dp*tmp
    1651            0 :                   IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    1652              :                      CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx_im, &
    1653            0 :                                     qs_ot_env(ispin)%rot_mat_gx_im, tmp)
    1654            0 :                      qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + 0.5_dp*tmp
    1655              :                   END IF
    1656              :                END DO
    1657              :             END IF
    1658              :          END IF
    1659           12 :          IF (do_ener) THEN
    1660            0 :             DO ispin = 1, nspin
    1661            0 :                IF (qs_ot_env(ispin)%settings%occupation_preconditioner) THEN
    1662              :                   tmp = DOT_PRODUCT(qs_ot_env(ispin)%ener_gx, &
    1663            0 :                                     qs_ot_env(ispin)%ener_preconditioned_gx)
    1664            0 :                   IF (tmp <= 0.0_dp) THEN
    1665            0 :                      qs_ot_env(ispin)%ener_preconditioned_gx = qs_ot_env(ispin)%ener_gx
    1666            0 :                      tmp = DOT_PRODUCT(qs_ot_env(ispin)%ener_gx, qs_ot_env(ispin)%ener_gx)
    1667              :                   END IF
    1668            0 :                   qs_ot_env(ispin)%ener_gx = qs_ot_env(ispin)%ener_preconditioned_gx
    1669              :                ELSE
    1670            0 :                   tmp = DOT_PRODUCT(qs_ot_env(ispin)%ener_gx, qs_ot_env(ispin)%ener_gx)
    1671              :                END IF
    1672            0 :                qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
    1673              :             END DO
    1674              :          END IF
    1675              :       END IF
    1676              : 
    1677           64 :       k = 0
    1678           64 :       n = 0
    1679           64 :       nener = 0
    1680           64 :       IF (do_ks) THEN
    1681           64 :          CALL dbcsr_get_info(qs_ot_env(1)%matrix_x, nfullrows_total=n)
    1682          154 :          DO ispin = 1, nspin
    1683           90 :             CALL dbcsr_get_info(qs_ot_env(ispin)%matrix_x, nfullcols_total=itmp)
    1684           90 :             k = k + itmp
    1685          154 :             IF (qs_ot_env(ispin)%has_complex_kpoint_state) k = k + itmp
    1686              :          END DO
    1687              :       END IF
    1688           64 :       IF (do_ener) THEN
    1689           78 :          DO ispin = 1, nspin
    1690           78 :             nener = nener + SIZE(qs_ot_env(ispin)%ener_x)
    1691              :          END DO
    1692              :       END IF
    1693           64 :       CALL ot_mini_sum_kpoint_scalar(para_env_inter_kp, qs_ot_env(1)%gnorm)
    1694           64 :       nvariables = REAL(INT(n, KIND=int_8)*INT(k, KIND=int_8) + nener, KIND=dp)
    1695           64 :       CALL ot_mini_sum_kpoint_scalar(para_env_inter_kp, nvariables)
    1696              :       ! Handling the case of no free variables to optimize
    1697           64 :       IF (nvariables > 0.0_dp) THEN
    1698           62 :          qs_ot_env(1)%delta = SQRT(ABS(qs_ot_env(1)%gnorm)/nvariables)
    1699           62 :          qs_ot_env(1)%gradient = -qs_ot_env(1)%gnorm
    1700              :       ELSE
    1701            2 :          qs_ot_env(1)%delta = 0.0_dp
    1702            2 :          qs_ot_env(1)%gradient = 0.0_dp
    1703              :       END IF
    1704              : 
    1705           64 :       CALL timestop(handle)
    1706              : 
    1707           64 :    END SUBROUTINE ot_new_sd_direction
    1708              : 
    1709              : !
    1710              : ! creates a new CG direction. Implements Polak-Ribierre variant
    1711              : ! using the preconditioner if associated
    1712              : ! also updates the gradient for line search
    1713              : !
    1714              : ! **************************************************************************************************
    1715              : !> \brief ...
    1716              : !> \param qs_ot_env ...
    1717              : !> \param para_env_inter_kp communicator between distributed k-point groups
    1718              : ! **************************************************************************************************
    1719        46160 :    SUBROUTINE ot_new_cg_direction(qs_ot_env, para_env_inter_kp)
    1720              :       TYPE(qs_ot_type), DIMENSION(:), POINTER            :: qs_ot_env
    1721              :       TYPE(mp_para_env_type), OPTIONAL, POINTER          :: para_env_inter_kp
    1722              : 
    1723              :       CHARACTER(len=*), PARAMETER :: routineN = 'ot_new_cg_direction'
    1724              : 
    1725              :       INTEGER                                            :: handle, ispin, itmp, k, n, nener, nspin
    1726              :       LOGICAL                                            :: do_ener, do_ks, &
    1727              :                                                             preceding_response_candidate, &
    1728              :                                                             use_response_candidate
    1729              :       REAL(KIND=dp)                                      :: baseline_delta, baseline_gnorm, beta_pr, &
    1730              :                                                             gnorm_cross, nvariables, test_down, tmp
    1731              :       TYPE(cp_logger_type), POINTER                      :: logger
    1732              : 
    1733              : ! Only the physical low-rank subspace solve can become active. The frozen-H response remains a
    1734              : ! shadow when that total projected Hessian is indefinite or unresolved.
    1735              : 
    1736        23080 :       CALL timeset(routineN, handle)
    1737              : 
    1738        23080 :       nspin = SIZE(qs_ot_env)
    1739        23080 :       logger => cp_get_default_logger()
    1740        23080 :       preceding_response_candidate = qs_ot_env(1)%response_candidate_pending
    1741              : 
    1742        23080 :       do_ks = qs_ot_env(1)%settings%ks
    1743        23080 :       do_ener = qs_ot_env(1)%settings%do_ener
    1744        23080 :       gnorm_cross = 0.0_dp
    1745        23080 :       IF (do_ks) THEN
    1746        51590 :          DO ispin = 1, nspin
    1747        28510 :             CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_gx_old, tmp)
    1748        28510 :             gnorm_cross = gnorm_cross + tmp
    1749        51590 :             IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    1750          983 :                CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx_im, qs_ot_env(ispin)%matrix_gx_old_im, tmp)
    1751          983 :                gnorm_cross = gnorm_cross + tmp
    1752              :             END IF
    1753              :          END DO
    1754        23080 :          IF (qs_ot_env(1)%settings%do_rotation) THEN
    1755         3495 :             DO ispin = 1, nspin
    1756         1841 :                CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx, qs_ot_env(ispin)%rot_mat_gx_old, tmp)
    1757              :                ! added 0.5, because we have (antisymmetry) only half the number of variables
    1758         1841 :                gnorm_cross = gnorm_cross + 0.5_dp*tmp
    1759         3495 :                IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    1760              :                   CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx_im, &
    1761          389 :                                  qs_ot_env(ispin)%rot_mat_gx_old_im, tmp)
    1762          389 :                   gnorm_cross = gnorm_cross + 0.5_dp*tmp
    1763              :                END IF
    1764              :             END DO
    1765              :          END IF
    1766              :       END IF
    1767        23080 :       IF (do_ener) THEN
    1768          596 :          DO ispin = 1, nspin
    1769         2520 :             tmp = DOT_PRODUCT(qs_ot_env(ispin)%ener_gx, qs_ot_env(ispin)%ener_gx_old)
    1770          596 :             gnorm_cross = gnorm_cross + tmp
    1771              :          END DO
    1772              :       END IF
    1773        23080 :       CALL ot_mini_sum_kpoint_scalar(para_env_inter_kp, gnorm_cross)
    1774              : 
    1775        23080 :       IF (ASSOCIATED(qs_ot_env(1)%preconditioner)) THEN
    1776              : 
    1777        40948 :          DO ispin = 1, nspin
    1778        40948 :             IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    1779          979 :                IF (qs_ot_env(ispin)%settings%occupation_preconditioner) THEN
    1780              :                   CALL apply_preconditioner(qs_ot_env(ispin)%preconditioner, &
    1781              :                                             qs_ot_env(ispin)%matrix_preconditioned_gx, &
    1782              :                                             qs_ot_env(ispin)%matrix_preconditioned_gx_im, &
    1783              :                                             qs_ot_env(ispin)%matrix_gx_old, &
    1784          344 :                                             qs_ot_env(ispin)%matrix_gx_old_im)
    1785              :                ELSE
    1786              :                   CALL apply_preconditioner(qs_ot_env(ispin)%preconditioner, &
    1787              :                                             qs_ot_env(ispin)%matrix_gx, &
    1788              :                                             qs_ot_env(ispin)%matrix_gx_im, &
    1789              :                                             qs_ot_env(ispin)%matrix_gx_old, &
    1790          635 :                                             qs_ot_env(ispin)%matrix_gx_old_im)
    1791              :                END IF
    1792          979 :                CPASSERT(qs_ot_env(ispin)%kpoint_weight > 0.0_dp)
    1793              :                CALL dbcsr_scale(qs_ot_env(ispin)%matrix_gx_old, &
    1794          979 :                                 qs_ot_kpoint_preconditioner_scale(qs_ot_env(ispin)%kpoint_weight))
    1795              :                CALL dbcsr_scale(qs_ot_env(ispin)%matrix_gx_old_im, &
    1796          979 :                                 qs_ot_kpoint_preconditioner_scale(qs_ot_env(ispin)%kpoint_weight))
    1797              :             ELSE
    1798        21969 :                IF (qs_ot_env(ispin)%settings%occupation_preconditioner) THEN
    1799              :                   CALL apply_preconditioner(qs_ot_env(ispin)%preconditioner, &
    1800              :                                             qs_ot_env(ispin)%matrix_preconditioned_gx, &
    1801            0 :                                             qs_ot_env(ispin)%matrix_gx_old)
    1802              :                ELSE
    1803              :                   CALL apply_preconditioner(qs_ot_env(ispin)%preconditioner, &
    1804        21969 :                                             qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_gx_old)
    1805              :                END IF
    1806              :             END IF
    1807              :          END DO
    1808        18000 :          qs_ot_env(1)%gnorm = 0.0_dp
    1809        18000 :          IF (do_ks) THEN
    1810        40948 :             DO ispin = 1, nspin
    1811        22948 :                CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_gx_old, tmp)
    1812        22948 :                qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
    1813        40948 :                IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    1814          979 :                   CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx_im, qs_ot_env(ispin)%matrix_gx_old_im, tmp)
    1815          979 :                   qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
    1816              :                END IF
    1817              :             END DO
    1818        18000 :             IF (.NOT. qs_ot_env(1)%settings%occupation_preconditioner) THEN
    1819        40352 :                DO ispin = 1, nspin
    1820        22604 :                   CALL dbcsr_copy(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_gx_old)
    1821        40352 :                   IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    1822              :                      CALL dbcsr_copy(qs_ot_env(ispin)%matrix_gx_im, &
    1823          635 :                                      qs_ot_env(ispin)%matrix_gx_old_im)
    1824              :                   END IF
    1825              :                END DO
    1826              :             END IF
    1827        18000 :             IF (qs_ot_env(1)%settings%do_rotation) THEN
    1828         3495 :                DO ispin = 1, nspin
    1829         1841 :                   CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_gx_old, qs_ot_env(ispin)%rot_mat_gx)
    1830         1841 :                   CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx, qs_ot_env(ispin)%rot_mat_gx_old, tmp)
    1831              :                   ! added 0.5, because we have (antisymmetry) only half the number of variables
    1832         1841 :                   qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + 0.5_dp*tmp
    1833         3495 :                   IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    1834              :                      CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_gx_old_im, &
    1835          389 :                                      qs_ot_env(ispin)%rot_mat_gx_im)
    1836              :                      CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx_im, &
    1837          389 :                                     qs_ot_env(ispin)%rot_mat_gx_old_im, tmp)
    1838          389 :                      qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + 0.5_dp*tmp
    1839              :                   END IF
    1840              :                END DO
    1841              :             END IF
    1842              :          END IF
    1843        18000 :          IF (do_ener) THEN
    1844          596 :             DO ispin = 1, nspin
    1845          344 :                IF (qs_ot_env(ispin)%settings%occupation_preconditioner) THEN
    1846         2520 :                   qs_ot_env(ispin)%ener_gx_old = qs_ot_env(ispin)%ener_preconditioned_gx
    1847              :                ELSE
    1848            0 :                   qs_ot_env(ispin)%ener_gx_old = qs_ot_env(ispin)%ener_gx
    1849              :                END IF
    1850         2520 :                tmp = DOT_PRODUCT(qs_ot_env(ispin)%ener_gx, qs_ot_env(ispin)%ener_gx_old)
    1851          596 :                qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
    1852              :             END DO
    1853              :          END IF
    1854              :       ELSE
    1855         5080 :          IF (do_ks) THEN
    1856         5080 :             qs_ot_env(1)%gnorm = 0.0_dp
    1857        10642 :             DO ispin = 1, nspin
    1858         5562 :                IF (qs_ot_env(ispin)%settings%occupation_preconditioner) THEN
    1859              :                   CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, &
    1860            0 :                                  qs_ot_env(ispin)%matrix_preconditioned_gx, tmp)
    1861              :                ELSE
    1862         5562 :                   CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_gx, tmp)
    1863              :                END IF
    1864         5562 :                qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
    1865         5562 :                IF (qs_ot_env(ispin)%settings%occupation_preconditioner) THEN
    1866              :                   CALL dbcsr_copy(qs_ot_env(ispin)%matrix_gx_old, &
    1867            0 :                                   qs_ot_env(ispin)%matrix_preconditioned_gx)
    1868              :                ELSE
    1869         5562 :                   CALL dbcsr_copy(qs_ot_env(ispin)%matrix_gx_old, qs_ot_env(ispin)%matrix_gx)
    1870              :                END IF
    1871        10642 :                IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    1872            4 :                   IF (qs_ot_env(ispin)%settings%occupation_preconditioner) THEN
    1873              :                      CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx_im, &
    1874            0 :                                     qs_ot_env(ispin)%matrix_preconditioned_gx_im, tmp)
    1875              :                   ELSE
    1876            4 :                      CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx_im, qs_ot_env(ispin)%matrix_gx_im, tmp)
    1877              :                   END IF
    1878            4 :                   qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
    1879            4 :                   IF (qs_ot_env(ispin)%settings%occupation_preconditioner) THEN
    1880              :                      CALL dbcsr_copy(qs_ot_env(ispin)%matrix_gx_old_im, &
    1881            0 :                                      qs_ot_env(ispin)%matrix_preconditioned_gx_im)
    1882              :                   ELSE
    1883            4 :                      CALL dbcsr_copy(qs_ot_env(ispin)%matrix_gx_old_im, qs_ot_env(ispin)%matrix_gx_im)
    1884              :                   END IF
    1885              :                END IF
    1886              :             END DO
    1887         5080 :             IF (qs_ot_env(1)%settings%do_rotation) THEN
    1888            0 :                DO ispin = 1, nspin
    1889            0 :                   CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx, qs_ot_env(ispin)%rot_mat_gx, tmp)
    1890              :                   ! added 0.5, because we have (antisymmetry) only half the number of variables
    1891            0 :                   qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + 0.5_dp*tmp
    1892            0 :                   CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_gx_old, qs_ot_env(ispin)%rot_mat_gx)
    1893            0 :                   IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    1894              :                      CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx_im, &
    1895            0 :                                     qs_ot_env(ispin)%rot_mat_gx_im, tmp)
    1896            0 :                      qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + 0.5_dp*tmp
    1897              :                      CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_gx_old_im, &
    1898            0 :                                      qs_ot_env(ispin)%rot_mat_gx_im)
    1899              :                   END IF
    1900              :                END DO
    1901              :             END IF
    1902              :          END IF
    1903         5080 :          IF (do_ener) THEN
    1904            0 :             DO ispin = 1, nspin
    1905            0 :                IF (qs_ot_env(ispin)%settings%occupation_preconditioner) THEN
    1906              :                   tmp = DOT_PRODUCT(qs_ot_env(ispin)%ener_gx, &
    1907            0 :                                     qs_ot_env(ispin)%ener_preconditioned_gx)
    1908            0 :                   qs_ot_env(ispin)%ener_gx_old = qs_ot_env(ispin)%ener_preconditioned_gx
    1909              :                ELSE
    1910            0 :                   tmp = DOT_PRODUCT(qs_ot_env(ispin)%ener_gx, qs_ot_env(ispin)%ener_gx)
    1911            0 :                   qs_ot_env(ispin)%ener_gx_old = qs_ot_env(ispin)%ener_gx
    1912              :                END IF
    1913            0 :                qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
    1914              :             END DO
    1915              :          END IF
    1916              :       END IF
    1917              : 
    1918        23080 :       CALL ot_mini_sum_kpoint_scalar(para_env_inter_kp, qs_ot_env(1)%gnorm)
    1919              :       IF (ASSOCIATED(qs_ot_env(1)%preconditioner) .AND. &
    1920        23080 :           .NOT. qs_ot_env(1)%settings%occupation_preconditioner .AND. &
    1921              :           qs_ot_env(1)%gnorm < 0.0_dp) THEN
    1922            0 :          WRITE (cp_logger_get_default_unit_nr(logger), *) "WARNING Preconditioner not positive definite !"
    1923              :       END IF
    1924              : 
    1925              :       ! Occupation-unweighted orbital and energy blocks are useful preconditioner inputs, but only
    1926              :       ! their coupled direction is relevant for Mermin descent. Fall back as a whole when that
    1927              :       ! direction is not descending; rejecting individual blocks would destroy the Schur coupling.
    1928        23080 :       IF (qs_ot_env(1)%settings%occupation_preconditioner .AND. qs_ot_env(1)%gnorm <= 0.0_dp) THEN
    1929            2 :          qs_ot_env(1)%gnorm = 0.0_dp
    1930            2 :          IF (do_ks) THEN
    1931            6 :             DO ispin = 1, nspin
    1932            4 :                IF (ASSOCIATED(qs_ot_env(1)%preconditioner)) THEN
    1933            4 :                   IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    1934              :                      CALL apply_preconditioner(qs_ot_env(ispin)%preconditioner, &
    1935              :                                                qs_ot_env(ispin)%matrix_gx, &
    1936              :                                                qs_ot_env(ispin)%matrix_gx_im, &
    1937              :                                                qs_ot_env(ispin)%matrix_gx_old, &
    1938            4 :                                                qs_ot_env(ispin)%matrix_gx_old_im)
    1939              :                      CALL dbcsr_scale(qs_ot_env(ispin)%matrix_gx_old, &
    1940            4 :                                       qs_ot_kpoint_preconditioner_scale(qs_ot_env(ispin)%kpoint_weight))
    1941              :                      CALL dbcsr_scale(qs_ot_env(ispin)%matrix_gx_old_im, &
    1942            4 :                                       qs_ot_kpoint_preconditioner_scale(qs_ot_env(ispin)%kpoint_weight))
    1943              :                   ELSE
    1944              :                      CALL apply_preconditioner(qs_ot_env(ispin)%preconditioner, &
    1945              :                                                qs_ot_env(ispin)%matrix_gx, &
    1946            0 :                                                qs_ot_env(ispin)%matrix_gx_old)
    1947              :                   END IF
    1948              :                ELSE
    1949            0 :                   CALL dbcsr_copy(qs_ot_env(ispin)%matrix_gx_old, qs_ot_env(ispin)%matrix_gx)
    1950            0 :                   IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    1951              :                      CALL dbcsr_copy(qs_ot_env(ispin)%matrix_gx_old_im, &
    1952            0 :                                      qs_ot_env(ispin)%matrix_gx_im)
    1953              :                   END IF
    1954              :                END IF
    1955            4 :                CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_gx_old, tmp)
    1956            4 :                qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
    1957            4 :                IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    1958              :                   CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx_im, &
    1959            4 :                                  qs_ot_env(ispin)%matrix_gx_old_im, tmp)
    1960            4 :                   qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
    1961              :                END IF
    1962           10 :                IF (qs_ot_env(1)%settings%do_rotation) THEN
    1963            4 :                   CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_gx_old, qs_ot_env(ispin)%rot_mat_gx)
    1964            4 :                   CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx, qs_ot_env(ispin)%rot_mat_gx_old, tmp)
    1965            4 :                   qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + 0.5_dp*tmp
    1966            4 :                   IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    1967              :                      CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_gx_old_im, &
    1968            4 :                                      qs_ot_env(ispin)%rot_mat_gx_im)
    1969              :                      CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx_im, &
    1970            4 :                                     qs_ot_env(ispin)%rot_mat_gx_old_im, tmp)
    1971            4 :                      qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + 0.5_dp*tmp
    1972              :                   END IF
    1973              :                END IF
    1974              :             END DO
    1975              :          END IF
    1976            2 :          IF (do_ener) THEN
    1977            6 :             DO ispin = 1, nspin
    1978           12 :                qs_ot_env(ispin)%ener_gx_old = qs_ot_env(ispin)%ener_gx
    1979              :                qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + &
    1980              :                                     DOT_PRODUCT(qs_ot_env(ispin)%ener_gx, &
    1981           14 :                                                 qs_ot_env(ispin)%ener_gx_old)
    1982              :             END DO
    1983              :          END IF
    1984            2 :          CALL ot_mini_sum_kpoint_scalar(para_env_inter_kp, qs_ot_env(1)%gnorm)
    1985              :       END IF
    1986        23080 :       baseline_gnorm = qs_ot_env(1)%gnorm
    1987              : 
    1988        23080 :       k = 0
    1989        23080 :       n = 0
    1990        23080 :       nener = 0
    1991        23080 :       IF (do_ks) THEN
    1992        23080 :          CALL dbcsr_get_info(qs_ot_env(1)%matrix_x, nfullrows_total=n)
    1993        51590 :          DO ispin = 1, nspin
    1994        28510 :             CALL dbcsr_get_info(qs_ot_env(ispin)%matrix_x, nfullcols_total=itmp)
    1995        28510 :             k = k + itmp
    1996        51590 :             IF (qs_ot_env(ispin)%has_complex_kpoint_state) k = k + itmp
    1997              :          END DO
    1998              :       END IF
    1999        23080 :       IF (do_ener) THEN
    2000          596 :          DO ispin = 1, nspin
    2001          596 :             nener = nener + SIZE(qs_ot_env(ispin)%ener_x)
    2002              :          END DO
    2003              :       END IF
    2004        23080 :       nvariables = REAL(INT(n, KIND=int_8)*INT(k, KIND=int_8) + nener, KIND=dp)
    2005        23080 :       CALL ot_mini_sum_kpoint_scalar(para_env_inter_kp, nvariables)
    2006              : 
    2007        23080 :       baseline_delta = 0.0_dp
    2008        23080 :       IF (nvariables > 0.0_dp) THEN
    2009        22970 :          baseline_delta = SQRT(ABS(baseline_gnorm)/nvariables)
    2010              :       END IF
    2011              : 
    2012              :       ! Keep convergence reporting tied to the conventional preconditioned residual. The finite
    2013              :       ! response is an accepted-step candidate, not a redefinition of the physical stopping test.
    2014        23080 :       qs_ot_env(1)%delta = baseline_delta
    2015        23080 :       IF (nvariables > 0.0_dp) THEN
    2016        22970 :          beta_pr = (qs_ot_env(1)%gnorm - gnorm_cross)/qs_ot_env(1)%gnorm_old
    2017              :       ELSE
    2018          110 :          beta_pr = 0.0_dp
    2019              :       END IF
    2020        23080 :       IF (preceding_response_candidate) beta_pr = 0.0_dp
    2021        23080 :       IF (cg_history_restart_required( &
    2022              :           qs_ot_env(1)%settings%occupation_preconditioner, qs_ot_env(1)%etotal, &
    2023            2 :           qs_ot_env(1)%response_reference_energy)) beta_pr = 0.0_dp
    2024        23080 :       beta_pr = MAX(beta_pr, 0.0_dp) ! reset to SD
    2025              : 
    2026        23080 :       test_down = 0.0_dp
    2027        23080 :       IF (do_ks) THEN
    2028        51590 :          DO ispin = 1, nspin
    2029              :             CALL dbcsr_add(qs_ot_env(ispin)%matrix_dx, qs_ot_env(ispin)%matrix_gx_old, &
    2030        28510 :                            alpha_scalar=beta_pr, beta_scalar=-1.0_dp)
    2031        28510 :             CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_dx, tmp)
    2032        28510 :             test_down = test_down + tmp
    2033        28510 :             IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    2034              :                CALL dbcsr_add(qs_ot_env(ispin)%matrix_dx_im, qs_ot_env(ispin)%matrix_gx_old_im, &
    2035          983 :                               alpha_scalar=beta_pr, beta_scalar=-1.0_dp)
    2036          983 :                CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx_im, qs_ot_env(ispin)%matrix_dx_im, tmp)
    2037          983 :                test_down = test_down + tmp
    2038              :             END IF
    2039        80100 :             IF (qs_ot_env(1)%settings%do_rotation) THEN
    2040              :                CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_dx, qs_ot_env(ispin)%rot_mat_gx_old, &
    2041         1841 :                               alpha_scalar=beta_pr, beta_scalar=-1.0_dp)
    2042         1841 :                CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx, qs_ot_env(ispin)%rot_mat_dx, tmp)
    2043         1841 :                test_down = test_down + 0.5_dp*tmp
    2044         1841 :                IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    2045              :                   CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_dx_im, &
    2046              :                                  qs_ot_env(ispin)%rot_mat_gx_old_im, &
    2047          389 :                                  alpha_scalar=beta_pr, beta_scalar=-1.0_dp)
    2048              :                   CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx_im, &
    2049          389 :                                  qs_ot_env(ispin)%rot_mat_dx_im, tmp)
    2050          389 :                   test_down = test_down + 0.5_dp*tmp
    2051              :                END IF
    2052              :             END IF
    2053              :          END DO
    2054              :       END IF
    2055        23080 :       IF (do_ener) THEN
    2056          596 :          DO ispin = 1, nspin
    2057              :             qs_ot_env(ispin)%ener_dx = beta_pr*qs_ot_env(ispin)%ener_dx - &
    2058         2520 :                                        qs_ot_env(ispin)%ener_gx_old
    2059         2520 :             tmp = DOT_PRODUCT(qs_ot_env(ispin)%ener_gx, qs_ot_env(ispin)%ener_dx)
    2060          596 :             test_down = test_down + tmp
    2061              :          END DO
    2062              :       END IF
    2063        23080 :       CALL ot_mini_sum_kpoint_scalar(para_env_inter_kp, test_down)
    2064              : 
    2065        23080 :       IF (test_down >= 0.0_dp) THEN ! reset to SD
    2066          633 :          beta_pr = 0.0_dp
    2067          633 :          IF (do_ks) THEN
    2068         1464 :             DO ispin = 1, nspin
    2069              :                CALL dbcsr_add(qs_ot_env(ispin)%matrix_dx, qs_ot_env(ispin)%matrix_gx_old, &
    2070          831 :                               alpha_scalar=beta_pr, beta_scalar=-1.0_dp)
    2071          831 :                IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    2072              :                   CALL dbcsr_add(qs_ot_env(ispin)%matrix_dx_im, qs_ot_env(ispin)%matrix_gx_old_im, &
    2073           13 :                                  alpha_scalar=beta_pr, beta_scalar=-1.0_dp)
    2074              :                END IF
    2075         1464 :                IF (qs_ot_env(1)%settings%do_rotation) THEN
    2076              :                   CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_dx, &
    2077              :                                  qs_ot_env(ispin)%rot_mat_gx_old, &
    2078           21 :                                  alpha_scalar=beta_pr, beta_scalar=-1.0_dp)
    2079           21 :                   IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    2080              :                      CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_dx_im, &
    2081              :                                     qs_ot_env(ispin)%rot_mat_gx_old_im, &
    2082            9 :                                     alpha_scalar=beta_pr, beta_scalar=-1.0_dp)
    2083              :                   END IF
    2084              :                END IF
    2085              :             END DO
    2086              :          END IF
    2087          633 :          IF (do_ener) THEN
    2088           10 :             DO ispin = 1, nspin
    2089              :                qs_ot_env(ispin)%ener_dx = beta_pr*qs_ot_env(ispin)%ener_dx - &
    2090           58 :                                           qs_ot_env(ispin)%ener_gx_old
    2091              :             END DO
    2092              :          END IF
    2093              :       END IF
    2094              : 
    2095              :       CALL ot_try_mermin_response_direction( &
    2096        23080 :          qs_ot_env, para_env_inter_kp, baseline_delta, test_down, use_response_candidate)
    2097              :       ! since we change the direction we have to adjust the gradient
    2098        23080 :       IF (use_response_candidate) THEN
    2099           10 :          qs_ot_env(1)%OT_METHOD_FULL = "OT CG-R"
    2100           10 :          qs_ot_env(1)%gradient = test_down
    2101              :       ELSE
    2102        23070 :          qs_ot_env(1)%gradient = beta_pr*qs_ot_env(1)%gradient - qs_ot_env(1)%gnorm
    2103              :       END IF
    2104        23080 :       qs_ot_env(1)%gnorm_old = qs_ot_env(1)%gnorm
    2105              : 
    2106        23080 :       CALL timestop(handle)
    2107              : 
    2108        23080 :    END SUBROUTINE ot_new_cg_direction
    2109              : 
    2110              : ! **************************************************************************************************
    2111              : !> \brief Returns the smallest shift y <- y + shift*s that meets relative L-BFGS curvature.
    2112              : !> \param sy scalar product s.y
    2113              : !> \param ss scalar product s.s
    2114              : !> \param yy scalar product y.y
    2115              : !> \param curvature_tol requested lower bound for (s.y)/sqrt((s.s)(y.y))
    2116              : !> \return non-negative finite damping shift, or zero when no valid shift is needed or available
    2117              : ! **************************************************************************************************
    2118          446 :    PURE FUNCTION lbfgs_curvature_damping_shift(sy, ss, yy, curvature_tol) RESULT(damping_shift)
    2119              :       REAL(KIND=dp), INTENT(IN)                          :: sy, ss, yy, curvature_tol
    2120              :       REAL(KIND=dp)                                      :: damping_shift
    2121              : 
    2122              :       REAL(KIND=dp)                                      :: curvature_discriminant, target_sy
    2123              : 
    2124          446 :       damping_shift = 0.0_dp
    2125              :       IF (.NOT. ieee_is_finite(sy) .OR. .NOT. ieee_is_finite(ss) .OR. &
    2126              :           .NOT. ieee_is_finite(yy) .OR. ss <= 0.0_dp .OR. yy <= 0.0_dp .OR. &
    2127          446 :           curvature_tol < 0.0_dp .OR. curvature_tol >= 1.0_dp) RETURN
    2128              : 
    2129          442 :       curvature_discriminant = MAX(0.0_dp, ss*yy - sy*sy)
    2130              :       target_sy = curvature_tol/SQRT(MAX(TINY(1.0_dp), 1.0_dp - curvature_tol**2))* &
    2131          442 :                   SQRT(curvature_discriminant)
    2132          442 :       IF (sy <= target_sy) THEN
    2133           32 :          target_sy = target_sy*(1.0_dp + SQRT(EPSILON(1.0_dp)))
    2134           32 :          damping_shift = MAX(0.0_dp, (target_sy - sy)/ss)
    2135           32 :          IF (.NOT. ieee_is_finite(damping_shift)) damping_shift = 0.0_dp
    2136              :       END IF
    2137              :    END FUNCTION lbfgs_curvature_damping_shift
    2138              : 
    2139              : ! **************************************************************************************************
    2140              : !> \brief Decides whether an L-BFGS history must be discarded after excessive gradient growth.
    2141              : !> \param current_gradient_norm_sq squared norm at the current accepted point
    2142              : !> \param previous_gradient_norm_sq squared norm at the preceding accepted point
    2143              : !> \return true when both norms are finite and the gradient grew by more than a factor of ten
    2144              : ! **************************************************************************************************
    2145          492 :    PURE FUNCTION lbfgs_history_restart_required(current_gradient_norm_sq, &
    2146              :                                                 previous_gradient_norm_sq) RESULT(restart_history)
    2147              :       REAL(KIND=dp), INTENT(IN)                          :: current_gradient_norm_sq, &
    2148              :                                                             previous_gradient_norm_sq
    2149              :       LOGICAL                                            :: restart_history
    2150              : 
    2151              :       REAL(KIND=dp), PARAMETER :: gradient_restart_factor = 10.0_dp
    2152              : 
    2153              :       restart_history = ieee_is_finite(current_gradient_norm_sq) .AND. &
    2154              :                         ieee_is_finite(previous_gradient_norm_sq) .AND. &
    2155              :                         previous_gradient_norm_sq > TINY(1.0_dp) .AND. &
    2156              :                         current_gradient_norm_sq > gradient_restart_factor**2* &
    2157          492 :                         previous_gradient_norm_sq
    2158          492 :    END FUNCTION lbfgs_history_restart_required
    2159              : 
    2160              : ! **************************************************************************************************
    2161              : !> \brief Decides whether L-BFGS must recover from a collapsed accepted line-search step.
    2162              : !> \param accepted_step step selected by the preceding line search
    2163              : !> \param reference_step configured initial line-search step
    2164              : !> \return true for a finite step smaller than one millionth of a valid reference step
    2165              : ! **************************************************************************************************
    2166          490 :    PURE FUNCTION lbfgs_step_restart_required(accepted_step, reference_step) RESULT(restart_step)
    2167              :       REAL(KIND=dp), INTENT(IN)                          :: accepted_step, reference_step
    2168              :       LOGICAL                                            :: restart_step
    2169              : 
    2170              :       REAL(KIND=dp), PARAMETER :: step_restart_factor = 1.0E-6_dp
    2171              : 
    2172              :       restart_step = ieee_is_finite(accepted_step) .AND. &
    2173              :                      ieee_is_finite(reference_step) .AND. &
    2174              :                      reference_step > 0.0_dp .AND. &
    2175          490 :                      ABS(accepted_step) < step_restart_factor*reference_step
    2176          490 :    END FUNCTION lbfgs_step_restart_required
    2177              : 
    2178              : ! **************************************************************************************************
    2179              : !> \brief Normalize and damp an occupation-response secant against the conventional H0 direction.
    2180              : !>
    2181              : !> The response direction is first normalized to the product norm of H0*g. If its directional
    2182              : !> derivative is smaller than the Powell bound, it is mixed with H0*g until
    2183              : !> g^T*p >= 0.2*g^T*H0*g. Equal-norm normalization and convex mixing bound the target direction,
    2184              : !> while the curvature bound keeps the inverse-BFGS completion positive and well conditioned.
    2185              : !> \param g_dot_response scalar product of g and the raw response direction
    2186              : !> \param response_norm_sq squared product norm of the raw response direction
    2187              : !> \param g_dot_h0_g scalar product of g and H0*g
    2188              : !> \param h0_g_norm_sq squared product norm of H0*g
    2189              : !> \param response_scale scale applied to the raw response direction
    2190              : !> \param response_weight convex weight of the normalized response direction
    2191              : !> \param valid true if finite positive input permits a response secant
    2192              : ! **************************************************************************************************
    2193          112 :    PURE SUBROUTINE lbfgs_response_secant_parameters( &
    2194              :       g_dot_response, response_norm_sq, g_dot_h0_g, h0_g_norm_sq, &
    2195              :       response_scale, response_weight, valid)
    2196              :       REAL(KIND=dp), INTENT(IN)                          :: g_dot_response, response_norm_sq, &
    2197              :                                                             g_dot_h0_g, h0_g_norm_sq
    2198              :       REAL(KIND=dp), INTENT(OUT)                         :: response_scale, response_weight
    2199              :       LOGICAL, INTENT(OUT)                               :: valid
    2200              : 
    2201              :       REAL(KIND=dp), PARAMETER                           :: powell_fraction = 0.2_dp
    2202              : 
    2203              :       REAL(KIND=dp)                                      :: scaled_curvature
    2204              : 
    2205          112 :       response_scale = 1.0_dp
    2206          112 :       response_weight = 0.0_dp
    2207              :       valid = ieee_is_finite(g_dot_response) .AND. &
    2208              :               ieee_is_finite(response_norm_sq) .AND. &
    2209              :               ieee_is_finite(g_dot_h0_g) .AND. &
    2210              :               ieee_is_finite(h0_g_norm_sq) .AND. &
    2211              :               g_dot_response > 0.0_dp .AND. &
    2212              :               response_norm_sq > TINY(1.0_dp) .AND. &
    2213              :               g_dot_h0_g > 0.0_dp .AND. &
    2214          112 :               h0_g_norm_sq > TINY(1.0_dp)
    2215          112 :       IF (.NOT. valid) RETURN
    2216              : 
    2217          108 :       response_scale = SQRT(h0_g_norm_sq/response_norm_sq)
    2218          108 :       scaled_curvature = response_scale*g_dot_response
    2219              :       IF (.NOT. ieee_is_finite(response_scale) .OR. &
    2220          108 :           .NOT. ieee_is_finite(scaled_curvature) .OR. scaled_curvature <= 0.0_dp) THEN
    2221            0 :          response_scale = 1.0_dp
    2222            0 :          valid = .FALSE.
    2223            0 :          RETURN
    2224              :       END IF
    2225              : 
    2226          108 :       response_weight = 1.0_dp
    2227          108 :       IF (scaled_curvature < powell_fraction*g_dot_h0_g) THEN
    2228              :          response_weight = (1.0_dp - powell_fraction)*g_dot_h0_g/ &
    2229           44 :                            (g_dot_h0_g - scaled_curvature)
    2230              :       END IF
    2231              :    END SUBROUTINE lbfgs_response_secant_parameters
    2232              : 
    2233              : ! **************************************************************************************************
    2234              : !> \brief Apply the L-BFGS initial inverse Hessian in the OT product space.
    2235              : !>
    2236              : !> The conventional OT preconditioner defines the base operator H0. If occupation response is
    2237              : !> enabled, a norm-bounded Powell-damped response direction p defines a positive inverse-BFGS
    2238              : !> secant completion. It maps the current physical gradient g to p while remaining a linear
    2239              : !> operator for the arbitrary vector q produced by the first L-BFGS loop:
    2240              : !>
    2241              : !> H = (I - rho*p*g^T)*H0*(I - rho*g*p^T) + rho*p*p^T,
    2242              : !>
    2243              : !> where rho = 1/(g^T*p). The m+1 history slot is scratch space for p; callers restore the current
    2244              : !> physical gradient there after this routine returns.
    2245              : !> \param qs_ot_env OT environments for all local spin/k-point channels
    2246              : !> \param gamma scalar H0 scale for orbital and energy variables without an OT preconditioner
    2247              : !> \param gamma_rotation H0 scale for rotation variables
    2248              : !> \param scratch_index history slot used to store p
    2249              : !> \param para_env_inter_kp communicator between distributed k-point groups
    2250              : ! **************************************************************************************************
    2251          706 :    SUBROUTINE ot_apply_lbfgs_initial_inverse( &
    2252              :       qs_ot_env, gamma, gamma_rotation, scratch_index, para_env_inter_kp)
    2253              :       TYPE(qs_ot_type), DIMENSION(:), POINTER            :: qs_ot_env
    2254              :       REAL(KIND=dp), INTENT(IN)                          :: gamma, gamma_rotation
    2255              :       INTEGER, INTENT(IN)                                :: scratch_index
    2256              :       TYPE(mp_para_env_type), OPTIONAL, POINTER          :: para_env_inter_kp
    2257              : 
    2258              :       INTEGER                                            :: ispin
    2259              :       LOGICAL                                            :: valid_response
    2260              :       REAL(KIND=dp) :: coeff_p, coeff_v, g_dot_h0_g, g_dot_h0_q, g_dot_p, h0_g_norm_sq, &
    2261              :          kpoint_scale, p_dot_q, p_norm_sq, response_scale, response_weight, rho, tmp
    2262              : 
    2263              :       ! Apply the base operator to q, which is stored in the *_gx_old work arrays.
    2264         1462 :       DO ispin = 1, SIZE(qs_ot_env)
    2265          860 :          IF (ASSOCIATED(qs_ot_env(1)%preconditioner)) THEN
    2266          860 :             IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    2267              :                CALL apply_preconditioner(qs_ot_env(ispin)%preconditioner, &
    2268              :                                          qs_ot_env(ispin)%matrix_gx_old, &
    2269              :                                          qs_ot_env(ispin)%matrix_gx_old_im, &
    2270              :                                          qs_ot_env(ispin)%matrix_dx, &
    2271          690 :                                          qs_ot_env(ispin)%matrix_dx_im)
    2272          690 :                CPASSERT(qs_ot_env(ispin)%kpoint_weight > 0.0_dp)
    2273              :                kpoint_scale = qs_ot_kpoint_preconditioner_scale( &
    2274          690 :                               qs_ot_env(ispin)%kpoint_weight)
    2275          690 :                CALL dbcsr_scale(qs_ot_env(ispin)%matrix_dx, kpoint_scale)
    2276          690 :                CALL dbcsr_scale(qs_ot_env(ispin)%matrix_dx_im, kpoint_scale)
    2277              :             ELSE
    2278              :                CALL apply_preconditioner(qs_ot_env(ispin)%preconditioner, &
    2279              :                                          qs_ot_env(ispin)%matrix_gx_old, &
    2280          170 :                                          qs_ot_env(ispin)%matrix_dx)
    2281              :             END IF
    2282              :          ELSE
    2283            0 :             CALL dbcsr_copy(qs_ot_env(ispin)%matrix_dx, qs_ot_env(ispin)%matrix_gx_old)
    2284            0 :             CALL dbcsr_scale(qs_ot_env(ispin)%matrix_dx, gamma)
    2285            0 :             IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    2286              :                CALL dbcsr_copy(qs_ot_env(ispin)%matrix_dx_im, &
    2287            0 :                                qs_ot_env(ispin)%matrix_gx_old_im)
    2288            0 :                CALL dbcsr_scale(qs_ot_env(ispin)%matrix_dx_im, gamma)
    2289              :             END IF
    2290              :          END IF
    2291          860 :          IF (qs_ot_env(1)%settings%do_rotation) THEN
    2292          626 :             CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_dx, qs_ot_env(ispin)%rot_mat_gx_old)
    2293          626 :             CALL dbcsr_scale(qs_ot_env(ispin)%rot_mat_dx, gamma_rotation)
    2294          626 :             IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    2295              :                CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_dx_im, &
    2296          562 :                                qs_ot_env(ispin)%rot_mat_gx_old_im)
    2297          562 :                CALL dbcsr_scale(qs_ot_env(ispin)%rot_mat_dx_im, gamma_rotation)
    2298              :             END IF
    2299              :          END IF
    2300         1462 :          IF (qs_ot_env(1)%settings%do_ener) THEN
    2301         2726 :             qs_ot_env(ispin)%ener_dx = gamma*qs_ot_env(ispin)%ener_gx_old
    2302              :          END IF
    2303              :       END DO
    2304          602 :       IF (.NOT. qs_ot_env(1)%settings%occupation_preconditioner) RETURN
    2305              : 
    2306              :       ! Build the desired occupation-preconditioned product direction p in the scratch slot.
    2307          260 :       DO ispin = 1, SIZE(qs_ot_env)
    2308          156 :          CPASSERT(ASSOCIATED(qs_ot_env(ispin)%matrix_preconditioned_gx))
    2309          156 :          IF (ASSOCIATED(qs_ot_env(1)%preconditioner)) THEN
    2310          156 :             IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    2311          156 :                CPASSERT(ASSOCIATED(qs_ot_env(ispin)%matrix_preconditioned_gx_im))
    2312              :                CALL apply_preconditioner(qs_ot_env(ispin)%preconditioner, &
    2313              :                                          qs_ot_env(ispin)%matrix_preconditioned_gx, &
    2314              :                                          qs_ot_env(ispin)%matrix_preconditioned_gx_im, &
    2315              :                                          qs_ot_env(ispin)%matrix_h_e(scratch_index)%matrix, &
    2316          156 :                                          qs_ot_env(ispin)%matrix_h_e_im(scratch_index)%matrix)
    2317              :                kpoint_scale = qs_ot_kpoint_preconditioner_scale( &
    2318          156 :                               qs_ot_env(ispin)%kpoint_weight)
    2319              :                CALL dbcsr_scale(qs_ot_env(ispin)%matrix_h_e(scratch_index)%matrix, &
    2320          156 :                                 kpoint_scale)
    2321              :                CALL dbcsr_scale(qs_ot_env(ispin)%matrix_h_e_im(scratch_index)%matrix, &
    2322          156 :                                 kpoint_scale)
    2323              :             ELSE
    2324              :                CALL apply_preconditioner(qs_ot_env(ispin)%preconditioner, &
    2325              :                                          qs_ot_env(ispin)%matrix_preconditioned_gx, &
    2326            0 :                                          qs_ot_env(ispin)%matrix_h_e(scratch_index)%matrix)
    2327              :             END IF
    2328              :          ELSE
    2329              :             CALL dbcsr_copy(qs_ot_env(ispin)%matrix_h_e(scratch_index)%matrix, &
    2330            0 :                             qs_ot_env(ispin)%matrix_preconditioned_gx)
    2331            0 :             IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    2332            0 :                CPASSERT(ASSOCIATED(qs_ot_env(ispin)%matrix_preconditioned_gx_im))
    2333              :                CALL dbcsr_copy(qs_ot_env(ispin)%matrix_h_e_im(scratch_index)%matrix, &
    2334            0 :                                qs_ot_env(ispin)%matrix_preconditioned_gx_im)
    2335              :             END IF
    2336              :          END IF
    2337          156 :          IF (qs_ot_env(1)%settings%do_rotation) THEN
    2338              :             CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_h_e(scratch_index)%matrix, &
    2339          156 :                             qs_ot_env(ispin)%rot_mat_gx)
    2340              :             CALL dbcsr_scale(qs_ot_env(ispin)%rot_mat_h_e(scratch_index)%matrix, &
    2341          156 :                              gamma_rotation)
    2342          156 :             IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    2343              :                CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_h_e_im(scratch_index)%matrix, &
    2344          156 :                                qs_ot_env(ispin)%rot_mat_gx_im)
    2345              :                CALL dbcsr_scale(qs_ot_env(ispin)%rot_mat_h_e_im(scratch_index)%matrix, &
    2346          156 :                                 gamma_rotation)
    2347              :             END IF
    2348              :          END IF
    2349          260 :          IF (qs_ot_env(1)%settings%do_ener) THEN
    2350          156 :             CPASSERT(ASSOCIATED(qs_ot_env(ispin)%ener_preconditioned_gx))
    2351              :             qs_ot_env(ispin)%ener_h_e(scratch_index, :) = &
    2352          932 :                qs_ot_env(ispin)%ener_preconditioned_gx
    2353              :          END IF
    2354              :       END DO
    2355              : 
    2356          104 :       g_dot_h0_q = 0.0_dp
    2357          104 :       g_dot_p = 0.0_dp
    2358          104 :       p_dot_q = 0.0_dp
    2359          104 :       p_norm_sq = 0.0_dp
    2360          260 :       DO ispin = 1, SIZE(qs_ot_env)
    2361          156 :          CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_dx, tmp)
    2362          156 :          g_dot_h0_q = g_dot_h0_q + tmp
    2363              :          CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, &
    2364          156 :                         qs_ot_env(ispin)%matrix_h_e(scratch_index)%matrix, tmp)
    2365          156 :          g_dot_p = g_dot_p + tmp
    2366              :          CALL dbcsr_dot(qs_ot_env(ispin)%matrix_h_e(scratch_index)%matrix, &
    2367          156 :                         qs_ot_env(ispin)%matrix_gx_old, tmp)
    2368          156 :          p_dot_q = p_dot_q + tmp
    2369              :          CALL dbcsr_dot(qs_ot_env(ispin)%matrix_h_e(scratch_index)%matrix, &
    2370          156 :                         qs_ot_env(ispin)%matrix_h_e(scratch_index)%matrix, tmp)
    2371          156 :          p_norm_sq = p_norm_sq + tmp
    2372          156 :          IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    2373              :             CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx_im, &
    2374          156 :                            qs_ot_env(ispin)%matrix_dx_im, tmp)
    2375          156 :             g_dot_h0_q = g_dot_h0_q + tmp
    2376              :             CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx_im, &
    2377          156 :                            qs_ot_env(ispin)%matrix_h_e_im(scratch_index)%matrix, tmp)
    2378          156 :             g_dot_p = g_dot_p + tmp
    2379              :             CALL dbcsr_dot(qs_ot_env(ispin)%matrix_h_e_im(scratch_index)%matrix, &
    2380          156 :                            qs_ot_env(ispin)%matrix_gx_old_im, tmp)
    2381          156 :             p_dot_q = p_dot_q + tmp
    2382              :             CALL dbcsr_dot(qs_ot_env(ispin)%matrix_h_e_im(scratch_index)%matrix, &
    2383          156 :                            qs_ot_env(ispin)%matrix_h_e_im(scratch_index)%matrix, tmp)
    2384          156 :             p_norm_sq = p_norm_sq + tmp
    2385              :          END IF
    2386          156 :          IF (qs_ot_env(1)%settings%do_rotation) THEN
    2387              :             CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx, &
    2388          156 :                            qs_ot_env(ispin)%rot_mat_dx, tmp)
    2389          156 :             g_dot_h0_q = g_dot_h0_q + 0.5_dp*tmp
    2390              :             CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx, &
    2391          156 :                            qs_ot_env(ispin)%rot_mat_h_e(scratch_index)%matrix, tmp)
    2392          156 :             g_dot_p = g_dot_p + 0.5_dp*tmp
    2393              :             CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_h_e(scratch_index)%matrix, &
    2394          156 :                            qs_ot_env(ispin)%rot_mat_gx_old, tmp)
    2395          156 :             p_dot_q = p_dot_q + 0.5_dp*tmp
    2396              :             CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_h_e(scratch_index)%matrix, &
    2397          156 :                            qs_ot_env(ispin)%rot_mat_h_e(scratch_index)%matrix, tmp)
    2398          156 :             p_norm_sq = p_norm_sq + 0.5_dp*tmp
    2399          156 :             IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    2400              :                CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx_im, &
    2401          156 :                               qs_ot_env(ispin)%rot_mat_dx_im, tmp)
    2402          156 :                g_dot_h0_q = g_dot_h0_q + 0.5_dp*tmp
    2403              :                CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx_im, &
    2404          156 :                               qs_ot_env(ispin)%rot_mat_h_e_im(scratch_index)%matrix, tmp)
    2405          156 :                g_dot_p = g_dot_p + 0.5_dp*tmp
    2406              :                CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_h_e_im(scratch_index)%matrix, &
    2407          156 :                               qs_ot_env(ispin)%rot_mat_gx_old_im, tmp)
    2408          156 :                p_dot_q = p_dot_q + 0.5_dp*tmp
    2409              :                CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_h_e_im(scratch_index)%matrix, &
    2410          156 :                               qs_ot_env(ispin)%rot_mat_h_e_im(scratch_index)%matrix, tmp)
    2411          156 :                p_norm_sq = p_norm_sq + 0.5_dp*tmp
    2412              :             END IF
    2413              :          END IF
    2414          416 :          IF (qs_ot_env(1)%settings%do_ener) THEN
    2415              :             g_dot_h0_q = g_dot_h0_q + &
    2416          932 :                          DOT_PRODUCT(qs_ot_env(ispin)%ener_gx, qs_ot_env(ispin)%ener_dx)
    2417              :             g_dot_p = g_dot_p + DOT_PRODUCT(qs_ot_env(ispin)%ener_gx, &
    2418          932 :                                             qs_ot_env(ispin)%ener_h_e(scratch_index, :))
    2419              :             p_dot_q = p_dot_q + DOT_PRODUCT(qs_ot_env(ispin)%ener_h_e(scratch_index, :), &
    2420          932 :                                             qs_ot_env(ispin)%ener_gx_old)
    2421              :             p_norm_sq = p_norm_sq + DOT_PRODUCT( &
    2422              :                         qs_ot_env(ispin)%ener_h_e(scratch_index, :), &
    2423          932 :                         qs_ot_env(ispin)%ener_h_e(scratch_index, :))
    2424              :          END IF
    2425              :       END DO
    2426          104 :       CALL ot_mini_sum_kpoint_scalar(para_env_inter_kp, g_dot_h0_q)
    2427          104 :       CALL ot_mini_sum_kpoint_scalar(para_env_inter_kp, g_dot_p)
    2428          104 :       CALL ot_mini_sum_kpoint_scalar(para_env_inter_kp, p_dot_q)
    2429          104 :       CALL ot_mini_sum_kpoint_scalar(para_env_inter_kp, p_norm_sq)
    2430              : 
    2431              :       ! Overwrite q with H0*g; q is no longer needed after p^T*q has been formed.
    2432          104 :       g_dot_h0_g = 0.0_dp
    2433          104 :       h0_g_norm_sq = 0.0_dp
    2434          260 :       DO ispin = 1, SIZE(qs_ot_env)
    2435          156 :          IF (ASSOCIATED(qs_ot_env(1)%preconditioner)) THEN
    2436          156 :             IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    2437              :                CALL apply_preconditioner(qs_ot_env(ispin)%preconditioner, &
    2438              :                                          qs_ot_env(ispin)%matrix_gx, &
    2439              :                                          qs_ot_env(ispin)%matrix_gx_im, &
    2440              :                                          qs_ot_env(ispin)%matrix_gx_old, &
    2441          156 :                                          qs_ot_env(ispin)%matrix_gx_old_im)
    2442              :                kpoint_scale = qs_ot_kpoint_preconditioner_scale( &
    2443          156 :                               qs_ot_env(ispin)%kpoint_weight)
    2444          156 :                CALL dbcsr_scale(qs_ot_env(ispin)%matrix_gx_old, kpoint_scale)
    2445          156 :                CALL dbcsr_scale(qs_ot_env(ispin)%matrix_gx_old_im, kpoint_scale)
    2446              :             ELSE
    2447              :                CALL apply_preconditioner(qs_ot_env(ispin)%preconditioner, &
    2448              :                                          qs_ot_env(ispin)%matrix_gx, &
    2449            0 :                                          qs_ot_env(ispin)%matrix_gx_old)
    2450              :             END IF
    2451              :          ELSE
    2452            0 :             CALL dbcsr_copy(qs_ot_env(ispin)%matrix_gx_old, qs_ot_env(ispin)%matrix_gx)
    2453            0 :             CALL dbcsr_scale(qs_ot_env(ispin)%matrix_gx_old, gamma)
    2454            0 :             IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    2455            0 :                CALL dbcsr_copy(qs_ot_env(ispin)%matrix_gx_old_im, qs_ot_env(ispin)%matrix_gx_im)
    2456            0 :                CALL dbcsr_scale(qs_ot_env(ispin)%matrix_gx_old_im, gamma)
    2457              :             END IF
    2458              :          END IF
    2459          156 :          CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_gx_old, tmp)
    2460          156 :          g_dot_h0_g = g_dot_h0_g + tmp
    2461              :          CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx_old, &
    2462          156 :                         qs_ot_env(ispin)%matrix_gx_old, tmp)
    2463          156 :          h0_g_norm_sq = h0_g_norm_sq + tmp
    2464          156 :          IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    2465              :             CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx_im, &
    2466          156 :                            qs_ot_env(ispin)%matrix_gx_old_im, tmp)
    2467          156 :             g_dot_h0_g = g_dot_h0_g + tmp
    2468              :             CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx_old_im, &
    2469          156 :                            qs_ot_env(ispin)%matrix_gx_old_im, tmp)
    2470          156 :             h0_g_norm_sq = h0_g_norm_sq + tmp
    2471              :          END IF
    2472          156 :          IF (qs_ot_env(1)%settings%do_rotation) THEN
    2473          156 :             CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_gx_old, qs_ot_env(ispin)%rot_mat_gx)
    2474          156 :             CALL dbcsr_scale(qs_ot_env(ispin)%rot_mat_gx_old, gamma_rotation)
    2475              :             CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx, &
    2476          156 :                            qs_ot_env(ispin)%rot_mat_gx_old, tmp)
    2477          156 :             g_dot_h0_g = g_dot_h0_g + 0.5_dp*tmp
    2478              :             CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx_old, &
    2479          156 :                            qs_ot_env(ispin)%rot_mat_gx_old, tmp)
    2480          156 :             h0_g_norm_sq = h0_g_norm_sq + 0.5_dp*tmp
    2481          156 :             IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    2482              :                CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_gx_old_im, &
    2483          156 :                                qs_ot_env(ispin)%rot_mat_gx_im)
    2484          156 :                CALL dbcsr_scale(qs_ot_env(ispin)%rot_mat_gx_old_im, gamma_rotation)
    2485              :                CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx_im, &
    2486          156 :                               qs_ot_env(ispin)%rot_mat_gx_old_im, tmp)
    2487          156 :                g_dot_h0_g = g_dot_h0_g + 0.5_dp*tmp
    2488              :                CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx_old_im, &
    2489          156 :                               qs_ot_env(ispin)%rot_mat_gx_old_im, tmp)
    2490          156 :                h0_g_norm_sq = h0_g_norm_sq + 0.5_dp*tmp
    2491              :             END IF
    2492              :          END IF
    2493          416 :          IF (qs_ot_env(1)%settings%do_ener) THEN
    2494          932 :             qs_ot_env(ispin)%ener_gx_old = gamma*qs_ot_env(ispin)%ener_gx
    2495              :             g_dot_h0_g = g_dot_h0_g + &
    2496              :                          DOT_PRODUCT(qs_ot_env(ispin)%ener_gx, &
    2497          932 :                                      qs_ot_env(ispin)%ener_gx_old)
    2498              :             h0_g_norm_sq = h0_g_norm_sq + &
    2499              :                            DOT_PRODUCT(qs_ot_env(ispin)%ener_gx_old, &
    2500          932 :                                        qs_ot_env(ispin)%ener_gx_old)
    2501              :          END IF
    2502              :       END DO
    2503          104 :       CALL ot_mini_sum_kpoint_scalar(para_env_inter_kp, g_dot_h0_g)
    2504          104 :       CALL ot_mini_sum_kpoint_scalar(para_env_inter_kp, h0_g_norm_sq)
    2505              : 
    2506              :       CALL lbfgs_response_secant_parameters( &
    2507              :          g_dot_p, p_norm_sq, g_dot_h0_g, h0_g_norm_sq, &
    2508          104 :          response_scale, response_weight, valid_response)
    2509          104 :       IF (.NOT. valid_response) RETURN
    2510              : 
    2511              :       ! Replace p by the bounded, damped response target and update its scalar products.
    2512          260 :       DO ispin = 1, SIZE(qs_ot_env)
    2513              :          CALL dbcsr_scale(qs_ot_env(ispin)%matrix_h_e(scratch_index)%matrix, &
    2514          156 :                           response_weight*response_scale)
    2515              :          CALL dbcsr_add(qs_ot_env(ispin)%matrix_h_e(scratch_index)%matrix, &
    2516              :                         qs_ot_env(ispin)%matrix_gx_old, &
    2517          156 :                         alpha_scalar=1.0_dp, beta_scalar=1.0_dp - response_weight)
    2518          156 :          IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    2519              :             CALL dbcsr_scale(qs_ot_env(ispin)%matrix_h_e_im(scratch_index)%matrix, &
    2520          156 :                              response_weight*response_scale)
    2521              :             CALL dbcsr_add(qs_ot_env(ispin)%matrix_h_e_im(scratch_index)%matrix, &
    2522              :                            qs_ot_env(ispin)%matrix_gx_old_im, &
    2523          156 :                            alpha_scalar=1.0_dp, beta_scalar=1.0_dp - response_weight)
    2524              :          END IF
    2525          156 :          IF (qs_ot_env(1)%settings%do_rotation) THEN
    2526              :             CALL dbcsr_scale(qs_ot_env(ispin)%rot_mat_h_e(scratch_index)%matrix, &
    2527          156 :                              response_weight*response_scale)
    2528              :             CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_h_e(scratch_index)%matrix, &
    2529              :                            qs_ot_env(ispin)%rot_mat_gx_old, &
    2530          156 :                            alpha_scalar=1.0_dp, beta_scalar=1.0_dp - response_weight)
    2531          156 :             IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    2532              :                CALL dbcsr_scale(qs_ot_env(ispin)%rot_mat_h_e_im(scratch_index)%matrix, &
    2533          156 :                                 response_weight*response_scale)
    2534              :                CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_h_e_im(scratch_index)%matrix, &
    2535              :                               qs_ot_env(ispin)%rot_mat_gx_old_im, &
    2536          156 :                               alpha_scalar=1.0_dp, beta_scalar=1.0_dp - response_weight)
    2537              :             END IF
    2538              :          END IF
    2539          260 :          IF (qs_ot_env(1)%settings%do_ener) THEN
    2540              :             qs_ot_env(ispin)%ener_h_e(scratch_index, :) = &
    2541              :                response_weight*response_scale*qs_ot_env(ispin)%ener_h_e(scratch_index, :) + &
    2542          932 :                (1.0_dp - response_weight)*qs_ot_env(ispin)%ener_gx_old
    2543              :          END IF
    2544              :       END DO
    2545              :       g_dot_p = response_weight*response_scale*g_dot_p + &
    2546          104 :                 (1.0_dp - response_weight)*g_dot_h0_g
    2547              :       p_dot_q = response_weight*response_scale*p_dot_q + &
    2548          104 :                 (1.0_dp - response_weight)*g_dot_h0_q
    2549              : 
    2550          104 :       rho = 1.0_dp/g_dot_p
    2551          104 :       coeff_p = -rho*g_dot_h0_q + p_dot_q*(rho + rho*rho*g_dot_h0_g)
    2552          104 :       coeff_v = -rho*p_dot_q
    2553          260 :       DO ispin = 1, SIZE(qs_ot_env)
    2554              :          CALL dbcsr_add(qs_ot_env(ispin)%matrix_dx, &
    2555              :                         qs_ot_env(ispin)%matrix_h_e(scratch_index)%matrix, &
    2556          156 :                         alpha_scalar=1.0_dp, beta_scalar=coeff_p)
    2557              :          CALL dbcsr_add(qs_ot_env(ispin)%matrix_dx, qs_ot_env(ispin)%matrix_gx_old, &
    2558          156 :                         alpha_scalar=1.0_dp, beta_scalar=coeff_v)
    2559          156 :          IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    2560              :             CALL dbcsr_add(qs_ot_env(ispin)%matrix_dx_im, &
    2561              :                            qs_ot_env(ispin)%matrix_h_e_im(scratch_index)%matrix, &
    2562          156 :                            alpha_scalar=1.0_dp, beta_scalar=coeff_p)
    2563              :             CALL dbcsr_add(qs_ot_env(ispin)%matrix_dx_im, &
    2564              :                            qs_ot_env(ispin)%matrix_gx_old_im, &
    2565          156 :                            alpha_scalar=1.0_dp, beta_scalar=coeff_v)
    2566              :          END IF
    2567          156 :          IF (qs_ot_env(1)%settings%do_rotation) THEN
    2568              :             CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_dx, &
    2569              :                            qs_ot_env(ispin)%rot_mat_h_e(scratch_index)%matrix, &
    2570          156 :                            alpha_scalar=1.0_dp, beta_scalar=coeff_p)
    2571              :             CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_dx, qs_ot_env(ispin)%rot_mat_gx_old, &
    2572          156 :                            alpha_scalar=1.0_dp, beta_scalar=coeff_v)
    2573          156 :             IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    2574              :                CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_dx_im, &
    2575              :                               qs_ot_env(ispin)%rot_mat_h_e_im(scratch_index)%matrix, &
    2576          156 :                               alpha_scalar=1.0_dp, beta_scalar=coeff_p)
    2577              :                CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_dx_im, &
    2578              :                               qs_ot_env(ispin)%rot_mat_gx_old_im, &
    2579          156 :                               alpha_scalar=1.0_dp, beta_scalar=coeff_v)
    2580              :             END IF
    2581              :          END IF
    2582          260 :          IF (qs_ot_env(1)%settings%do_ener) THEN
    2583              :             qs_ot_env(ispin)%ener_dx = qs_ot_env(ispin)%ener_dx + &
    2584              :                                        coeff_p*qs_ot_env(ispin)%ener_h_e(scratch_index, :) + &
    2585          932 :                                        coeff_v*qs_ot_env(ispin)%ener_gx_old
    2586              :          END IF
    2587              :       END DO
    2588              :    END SUBROUTINE ot_apply_lbfgs_initial_inverse
    2589              : 
    2590              : ! **************************************************************************************************
    2591              : !> \brief Builds an L-BFGS direction in the fixed OT product chart.
    2592              : !>
    2593              : !> The selected OT preconditioner is used as the initial inverse Hessian. History slot m+1 stores
    2594              : !> the previous accepted point and gradient; slots 1:m store the circular (s,y) secant history.
    2595              : !> Orbital rotations are included with the antisymmetric-matrix metric used by the other OT
    2596              : !> minimizers. Weak curvature can be regularized along the step, while rejected updates leave
    2597              : !> older valid history intact. Non-descent directions and collapsed line-search steps reset the
    2598              : !> history; the latter also restore the configured initial step.
    2599              : !> \param qs_ot_env OT environments for all local spin/k-point channels
    2600              : !> \param para_env_inter_kp communicator between distributed k-point groups
    2601              : ! **************************************************************************************************
    2602          602 :    SUBROUTINE ot_new_lbfgs_direction(qs_ot_env, para_env_inter_kp)
    2603              :       TYPE(qs_ot_type), DIMENSION(:), POINTER            :: qs_ot_env
    2604              :       TYPE(mp_para_env_type), OPTIONAL, POINTER          :: para_env_inter_kp
    2605              : 
    2606              :       CHARACTER(len=*), PARAMETER :: routineN = 'ot_new_lbfgs_direction'
    2607              :       REAL(KIND=dp), PARAMETER                           :: rotation_scale_max = 1.0E3_dp, &
    2608              :                                                             rotation_scale_min = 1.0E-3_dp
    2609              : 
    2610              :       INTEGER                                            :: handle, i, ispin, itmp, j, k, m_history, &
    2611              :                                                             n, nener, newest, nhistory, nspin
    2612              :       INTEGER(KIND=int_8)                                :: nrotation, nvariables
    2613          602 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: history_index
    2614              :       LOGICAL                                            :: do_ener, preceding_response_candidate, &
    2615              :                                                             restart_history, restart_step, &
    2616              :                                                             use_response_candidate
    2617              :       REAL(KIND=dp) :: beta, current_gradient_norm_sq, curvature_tol, damping_shift, g_dot_z, &
    2618              :          gamma, gamma_rotation, nvariables_global, previous_gradient_norm_sq, ss, ss_rotation, &
    2619              :          stq, sy, sy_rotation, test_down, tmp, yy, yy_newest, yy_rotation
    2620          602 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: alpha, rho
    2621              : 
    2622          602 :       CALL timeset(routineN, handle)
    2623              : 
    2624          602 :       IF (.NOT. qs_ot_env(1)%settings%ks) THEN
    2625            0 :          CPABORT("MINIMIZER LBFGS currently requires OT orbital variables")
    2626              :       END IF
    2627          602 :       nspin = SIZE(qs_ot_env)
    2628          602 :       do_ener = qs_ot_env(1)%settings%do_ener
    2629          602 :       m_history = qs_ot_env(1)%settings%diis_m
    2630          602 :       curvature_tol = qs_ot_env(1)%settings%lbfgs_curvature_tol
    2631          602 :       restart_history = .FALSE.
    2632          602 :       restart_step = .FALSE.
    2633          602 :       preceding_response_candidate = qs_ot_env(1)%response_candidate_pending
    2634              : 
    2635              :       ! A local line search can accept a nearly isoenergetic point whose raw gradient is much
    2636              :       ! larger than at the preceding point. CG naturally resets after such a loss of conjugacy,
    2637              :       ! whereas retaining an L-BFGS model can amplify it. Discard only the secant model and use
    2638              :       ! the physical initial inverse Hessian for the current direction. Likewise, restore the
    2639              :       ! configured initial step if repeated interpolation has collapsed the accepted step by more
    2640              :       ! than six orders of magnitude without satisfying the SCF convergence criterion.
    2641          602 :       IF (qs_ot_env(1)%diis_iter > 0) THEN
    2642          476 :          current_gradient_norm_sq = 0.0_dp
    2643          476 :          previous_gradient_norm_sq = 0.0_dp
    2644         1174 :          DO ispin = 1, nspin
    2645          698 :             CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_gx, tmp)
    2646          698 :             current_gradient_norm_sq = current_gradient_norm_sq + tmp
    2647              :             CALL dbcsr_dot(qs_ot_env(ispin)%matrix_h_e(m_history + 1)%matrix, &
    2648          698 :                            qs_ot_env(ispin)%matrix_h_e(m_history + 1)%matrix, tmp)
    2649          698 :             previous_gradient_norm_sq = previous_gradient_norm_sq + tmp
    2650          698 :             IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    2651              :                CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx_im, &
    2652          540 :                               qs_ot_env(ispin)%matrix_gx_im, tmp)
    2653          540 :                current_gradient_norm_sq = current_gradient_norm_sq + tmp
    2654              :                CALL dbcsr_dot(qs_ot_env(ispin)%matrix_h_e_im(m_history + 1)%matrix, &
    2655          540 :                               qs_ot_env(ispin)%matrix_h_e_im(m_history + 1)%matrix, tmp)
    2656          540 :                previous_gradient_norm_sq = previous_gradient_norm_sq + tmp
    2657              :             END IF
    2658          698 :             IF (qs_ot_env(1)%settings%do_rotation) THEN
    2659          560 :                CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx, qs_ot_env(ispin)%rot_mat_gx, tmp)
    2660          560 :                current_gradient_norm_sq = current_gradient_norm_sq + 0.5_dp*tmp
    2661              :                CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_h_e(m_history + 1)%matrix, &
    2662          560 :                               qs_ot_env(ispin)%rot_mat_h_e(m_history + 1)%matrix, tmp)
    2663          560 :                previous_gradient_norm_sq = previous_gradient_norm_sq + 0.5_dp*tmp
    2664          560 :                IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    2665              :                   CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx_im, &
    2666          500 :                                  qs_ot_env(ispin)%rot_mat_gx_im, tmp)
    2667          500 :                   current_gradient_norm_sq = current_gradient_norm_sq + 0.5_dp*tmp
    2668              :                   CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_h_e_im(m_history + 1)%matrix, &
    2669          500 :                                  qs_ot_env(ispin)%rot_mat_h_e_im(m_history + 1)%matrix, tmp)
    2670          500 :                   previous_gradient_norm_sq = previous_gradient_norm_sq + 0.5_dp*tmp
    2671              :                END IF
    2672              :             END IF
    2673         1872 :             IF (do_ener) THEN
    2674         2542 :                tmp = DOT_PRODUCT(qs_ot_env(ispin)%ener_gx, qs_ot_env(ispin)%ener_gx)
    2675          214 :                current_gradient_norm_sq = current_gradient_norm_sq + tmp
    2676              :                tmp = DOT_PRODUCT(qs_ot_env(ispin)%ener_h_e(m_history + 1, :), &
    2677         2542 :                                  qs_ot_env(ispin)%ener_h_e(m_history + 1, :))
    2678          214 :                previous_gradient_norm_sq = previous_gradient_norm_sq + tmp
    2679              :             END IF
    2680              :          END DO
    2681          476 :          CALL ot_mini_sum_kpoint_scalar(para_env_inter_kp, current_gradient_norm_sq)
    2682          476 :          CALL ot_mini_sum_kpoint_scalar(para_env_inter_kp, previous_gradient_norm_sq)
    2683              :          restart_step = lbfgs_step_restart_required(qs_ot_env(1)%ds_min, &
    2684          476 :                                                     qs_ot_env(1)%settings%ds_min)
    2685              :          restart_history = lbfgs_history_restart_required(current_gradient_norm_sq, &
    2686              :                                                           previous_gradient_norm_sq) .OR. &
    2687          476 :                            restart_step .OR. preceding_response_candidate
    2688              :          IF (restart_history) THEN
    2689            6 :             qs_ot_env(1)%diis_iter = 1
    2690            6 :             IF (restart_step) qs_ot_env(1)%ds_min = qs_ot_env(1)%settings%ds_min
    2691            6 :             qs_ot_env(1)%OT_METHOD_FULL = "OT L-RST"
    2692              :          END IF
    2693              :       END IF
    2694              : 
    2695              :       ! Form a candidate secant pair in the direction workspaces relative to the preceding
    2696              :       ! accepted line-search point. Commit it to the circular history only after the curvature
    2697              :       ! test, so a rejected candidate cannot overwrite the oldest valid pair in a full buffer.
    2698          602 :       IF (qs_ot_env(1)%diis_iter > 0 .AND. .NOT. restart_history) THEN
    2699          470 :          j = MOD(qs_ot_env(1)%diis_iter - 1, m_history) + 1
    2700          470 :          ss = 0.0_dp
    2701          470 :          sy = 0.0_dp
    2702          470 :          sy_rotation = 0.0_dp
    2703          470 :          ss_rotation = 0.0_dp
    2704          470 :          yy = 0.0_dp
    2705          470 :          yy_rotation = 0.0_dp
    2706         1160 :          DO ispin = 1, nspin
    2707          690 :             CALL dbcsr_copy(qs_ot_env(ispin)%matrix_dx, qs_ot_env(ispin)%matrix_x)
    2708              :             CALL dbcsr_add(qs_ot_env(ispin)%matrix_dx, &
    2709              :                            qs_ot_env(ispin)%matrix_h_x(m_history + 1)%matrix, &
    2710          690 :                            alpha_scalar=1.0_dp, beta_scalar=-1.0_dp)
    2711          690 :             CALL dbcsr_copy(qs_ot_env(ispin)%matrix_gx_old, qs_ot_env(ispin)%matrix_gx)
    2712              :             CALL dbcsr_add(qs_ot_env(ispin)%matrix_gx_old, &
    2713              :                            qs_ot_env(ispin)%matrix_h_e(m_history + 1)%matrix, &
    2714          690 :                            alpha_scalar=1.0_dp, beta_scalar=-1.0_dp)
    2715          690 :             CALL dbcsr_dot(qs_ot_env(ispin)%matrix_dx, qs_ot_env(ispin)%matrix_dx, tmp)
    2716          690 :             ss = ss + tmp
    2717          690 :             CALL dbcsr_dot(qs_ot_env(ispin)%matrix_dx, qs_ot_env(ispin)%matrix_gx_old, tmp)
    2718          690 :             sy = sy + tmp
    2719          690 :             CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx_old, qs_ot_env(ispin)%matrix_gx_old, tmp)
    2720          690 :             yy = yy + tmp
    2721          690 :             IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    2722          532 :                CALL dbcsr_copy(qs_ot_env(ispin)%matrix_dx_im, qs_ot_env(ispin)%matrix_x_im)
    2723              :                CALL dbcsr_add(qs_ot_env(ispin)%matrix_dx_im, &
    2724              :                               qs_ot_env(ispin)%matrix_h_x_im(m_history + 1)%matrix, &
    2725          532 :                               alpha_scalar=1.0_dp, beta_scalar=-1.0_dp)
    2726          532 :                CALL dbcsr_copy(qs_ot_env(ispin)%matrix_gx_old_im, qs_ot_env(ispin)%matrix_gx_im)
    2727              :                CALL dbcsr_add(qs_ot_env(ispin)%matrix_gx_old_im, &
    2728              :                               qs_ot_env(ispin)%matrix_h_e_im(m_history + 1)%matrix, &
    2729          532 :                               alpha_scalar=1.0_dp, beta_scalar=-1.0_dp)
    2730              :                CALL dbcsr_dot(qs_ot_env(ispin)%matrix_dx_im, &
    2731          532 :                               qs_ot_env(ispin)%matrix_dx_im, tmp)
    2732          532 :                ss = ss + tmp
    2733              :                CALL dbcsr_dot(qs_ot_env(ispin)%matrix_dx_im, &
    2734          532 :                               qs_ot_env(ispin)%matrix_gx_old_im, tmp)
    2735          532 :                sy = sy + tmp
    2736              :                CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx_old_im, &
    2737          532 :                               qs_ot_env(ispin)%matrix_gx_old_im, tmp)
    2738          532 :                yy = yy + tmp
    2739              :             END IF
    2740          690 :             IF (qs_ot_env(1)%settings%do_rotation) THEN
    2741          552 :                CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_dx, qs_ot_env(ispin)%rot_mat_x)
    2742              :                CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_dx, &
    2743              :                               qs_ot_env(ispin)%rot_mat_h_x(m_history + 1)%matrix, &
    2744          552 :                               alpha_scalar=1.0_dp, beta_scalar=-1.0_dp)
    2745          552 :                CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_gx_old, qs_ot_env(ispin)%rot_mat_gx)
    2746              :                CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_gx_old, &
    2747              :                               qs_ot_env(ispin)%rot_mat_h_e(m_history + 1)%matrix, &
    2748          552 :                               alpha_scalar=1.0_dp, beta_scalar=-1.0_dp)
    2749          552 :                CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_dx, qs_ot_env(ispin)%rot_mat_dx, tmp)
    2750          552 :                ss = ss + 0.5_dp*tmp
    2751          552 :                ss_rotation = ss_rotation + 0.5_dp*tmp
    2752          552 :                CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_dx, qs_ot_env(ispin)%rot_mat_gx_old, tmp)
    2753          552 :                sy = sy + 0.5_dp*tmp
    2754          552 :                sy_rotation = sy_rotation + 0.5_dp*tmp
    2755          552 :                CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx_old, qs_ot_env(ispin)%rot_mat_gx_old, tmp)
    2756          552 :                yy = yy + 0.5_dp*tmp
    2757          552 :                yy_rotation = yy_rotation + 0.5_dp*tmp
    2758          552 :                IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    2759          492 :                   CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_dx_im, qs_ot_env(ispin)%rot_mat_x_im)
    2760              :                   CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_dx_im, &
    2761              :                                  qs_ot_env(ispin)%rot_mat_h_x_im(m_history + 1)%matrix, &
    2762          492 :                                  alpha_scalar=1.0_dp, beta_scalar=-1.0_dp)
    2763              :                   CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_gx_old_im, &
    2764          492 :                                   qs_ot_env(ispin)%rot_mat_gx_im)
    2765              :                   CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_gx_old_im, &
    2766              :                                  qs_ot_env(ispin)%rot_mat_h_e_im(m_history + 1)%matrix, &
    2767          492 :                                  alpha_scalar=1.0_dp, beta_scalar=-1.0_dp)
    2768              :                   CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_dx_im, &
    2769          492 :                                  qs_ot_env(ispin)%rot_mat_dx_im, tmp)
    2770          492 :                   ss = ss + 0.5_dp*tmp
    2771          492 :                   ss_rotation = ss_rotation + 0.5_dp*tmp
    2772              :                   CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_dx_im, &
    2773          492 :                                  qs_ot_env(ispin)%rot_mat_gx_old_im, tmp)
    2774          492 :                   sy = sy + 0.5_dp*tmp
    2775          492 :                   sy_rotation = sy_rotation + 0.5_dp*tmp
    2776              :                   CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx_old_im, &
    2777          492 :                                  qs_ot_env(ispin)%rot_mat_gx_old_im, tmp)
    2778          492 :                   yy = yy + 0.5_dp*tmp
    2779          492 :                   yy_rotation = yy_rotation + 0.5_dp*tmp
    2780              :                END IF
    2781              :             END IF
    2782         1850 :             IF (do_ener) THEN
    2783              :                qs_ot_env(ispin)%ener_dx = qs_ot_env(ispin)%ener_x - &
    2784         2486 :                                           qs_ot_env(ispin)%ener_h_x(m_history + 1, :)
    2785              :                qs_ot_env(ispin)%ener_gx_old = qs_ot_env(ispin)%ener_gx - &
    2786         2486 :                                               qs_ot_env(ispin)%ener_h_e(m_history + 1, :)
    2787         2486 :                ss = ss + DOT_PRODUCT(qs_ot_env(ispin)%ener_dx, qs_ot_env(ispin)%ener_dx)
    2788         2486 :                sy = sy + DOT_PRODUCT(qs_ot_env(ispin)%ener_dx, qs_ot_env(ispin)%ener_gx_old)
    2789         2486 :                yy = yy + DOT_PRODUCT(qs_ot_env(ispin)%ener_gx_old, qs_ot_env(ispin)%ener_gx_old)
    2790              :             END IF
    2791              :          END DO
    2792          470 :          CALL ot_mini_sum_kpoint_scalar(para_env_inter_kp, ss)
    2793          470 :          CALL ot_mini_sum_kpoint_scalar(para_env_inter_kp, sy)
    2794          470 :          CALL ot_mini_sum_kpoint_scalar(para_env_inter_kp, yy)
    2795          470 :          CALL ot_mini_sum_kpoint_scalar(para_env_inter_kp, ss_rotation)
    2796          470 :          CALL ot_mini_sum_kpoint_scalar(para_env_inter_kp, sy_rotation)
    2797          470 :          CALL ot_mini_sum_kpoint_scalar(para_env_inter_kp, yy_rotation)
    2798              : 
    2799              :          ! Shift y along s just enough to satisfy the requested relative curvature. With the
    2800              :          ! product-chart metric this preserves orbital-rotation covariance. The target below is
    2801              :          ! obtained by solving (s.y)^2 >= tol^2 (s.s)(y.y) for y <- y + shift*s.
    2802          470 :          damping_shift = 0.0_dp
    2803          470 :          IF (qs_ot_env(1)%settings%lbfgs_damping) THEN
    2804          436 :             damping_shift = lbfgs_curvature_damping_shift(sy, ss, yy, curvature_tol)
    2805              :          END IF
    2806          470 :          IF (damping_shift > 0.0_dp) THEN
    2807           56 :             DO ispin = 1, nspin
    2808              :                CALL dbcsr_add(qs_ot_env(ispin)%matrix_gx_old, &
    2809              :                               qs_ot_env(ispin)%matrix_dx, &
    2810           28 :                               alpha_scalar=1.0_dp, beta_scalar=damping_shift)
    2811           28 :                IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    2812              :                   CALL dbcsr_add(qs_ot_env(ispin)%matrix_gx_old_im, &
    2813              :                                  qs_ot_env(ispin)%matrix_dx_im, &
    2814            0 :                                  alpha_scalar=1.0_dp, beta_scalar=damping_shift)
    2815              :                END IF
    2816           28 :                IF (qs_ot_env(1)%settings%do_rotation) THEN
    2817              :                   CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_gx_old, &
    2818              :                                  qs_ot_env(ispin)%rot_mat_dx, &
    2819            0 :                                  alpha_scalar=1.0_dp, beta_scalar=damping_shift)
    2820            0 :                   IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    2821              :                      CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_gx_old_im, &
    2822              :                                     qs_ot_env(ispin)%rot_mat_dx_im, &
    2823            0 :                                     alpha_scalar=1.0_dp, beta_scalar=damping_shift)
    2824              :                   END IF
    2825              :                END IF
    2826           56 :                IF (do_ener) THEN
    2827              :                   qs_ot_env(ispin)%ener_gx_old = qs_ot_env(ispin)%ener_gx_old + &
    2828            0 :                                                  damping_shift*qs_ot_env(ispin)%ener_dx
    2829              :                END IF
    2830              :             END DO
    2831           28 :             yy = yy + 2.0_dp*damping_shift*sy + damping_shift**2*ss
    2832              :             yy_rotation = yy_rotation + 2.0_dp*damping_shift*sy_rotation + &
    2833           28 :                           damping_shift**2*ss_rotation
    2834           28 :             sy = sy + damping_shift*ss
    2835           28 :             sy_rotation = sy_rotation + damping_shift*ss_rotation
    2836              :          END IF
    2837              :          IF (ieee_is_finite(sy) .AND. ieee_is_finite(ss) .AND. ieee_is_finite(yy) .AND. &
    2838          470 :              ss > 0.0_dp .AND. yy > 0.0_dp .AND. sy > curvature_tol*SQRT(ss*yy)) THEN
    2839         1148 :             DO ispin = 1, nspin
    2840              :                CALL dbcsr_copy(qs_ot_env(ispin)%matrix_h_x(j)%matrix, &
    2841          684 :                                qs_ot_env(ispin)%matrix_dx)
    2842              :                CALL dbcsr_copy(qs_ot_env(ispin)%matrix_h_e(j)%matrix, &
    2843          684 :                                qs_ot_env(ispin)%matrix_gx_old)
    2844          684 :                IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    2845              :                   CALL dbcsr_copy(qs_ot_env(ispin)%matrix_h_x_im(j)%matrix, &
    2846          532 :                                   qs_ot_env(ispin)%matrix_dx_im)
    2847              :                   CALL dbcsr_copy(qs_ot_env(ispin)%matrix_h_e_im(j)%matrix, &
    2848          532 :                                   qs_ot_env(ispin)%matrix_gx_old_im)
    2849              :                END IF
    2850          684 :                IF (qs_ot_env(1)%settings%do_rotation) THEN
    2851              :                   CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_h_x(j)%matrix, &
    2852          552 :                                   qs_ot_env(ispin)%rot_mat_dx)
    2853              :                   CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_h_e(j)%matrix, &
    2854          552 :                                   qs_ot_env(ispin)%rot_mat_gx_old)
    2855          552 :                   IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    2856              :                      CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_h_x_im(j)%matrix, &
    2857          492 :                                      qs_ot_env(ispin)%rot_mat_dx_im)
    2858              :                      CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_h_e_im(j)%matrix, &
    2859          492 :                                      qs_ot_env(ispin)%rot_mat_gx_old_im)
    2860              :                   END IF
    2861              :                END IF
    2862         1148 :                IF (do_ener) THEN
    2863         2486 :                   qs_ot_env(ispin)%ener_h_x(j, :) = qs_ot_env(ispin)%ener_dx
    2864         2486 :                   qs_ot_env(ispin)%ener_h_e(j, :) = qs_ot_env(ispin)%ener_gx_old
    2865              :                END IF
    2866              :             END DO
    2867          464 :             qs_ot_env(1)%lbfgs_rho(j) = 1.0_dp/sy
    2868          464 :             qs_ot_env(1)%lbfgs_yy(j) = yy
    2869          464 :             qs_ot_env(1)%lbfgs_sy_rotation(j) = sy_rotation
    2870          464 :             qs_ot_env(1)%lbfgs_yy_rotation(j) = yy_rotation
    2871          464 :             qs_ot_env(1)%diis_iter = qs_ot_env(1)%diis_iter + 1
    2872              :          ELSE
    2873              :             ! Skip this pair. Older pairs remain valid in the fixed OT chart and are retained;
    2874              :             ! the descent safeguard below still clears all history if their recursion fails.
    2875            6 :             qs_ot_env(1)%OT_METHOD_FULL = "OT LSKIP"
    2876              :          END IF
    2877          132 :       ELSE IF (qs_ot_env(1)%diis_iter <= 0) THEN
    2878          126 :          qs_ot_env(1)%diis_iter = 1
    2879              :       END IF
    2880              : 
    2881         1462 :       DO ispin = 1, nspin
    2882          860 :          CALL dbcsr_copy(qs_ot_env(ispin)%matrix_gx_old, qs_ot_env(ispin)%matrix_gx)
    2883          860 :          IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    2884          690 :             CALL dbcsr_copy(qs_ot_env(ispin)%matrix_gx_old_im, qs_ot_env(ispin)%matrix_gx_im)
    2885              :          END IF
    2886          860 :          IF (qs_ot_env(1)%settings%do_rotation) THEN
    2887          626 :             CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_gx_old, qs_ot_env(ispin)%rot_mat_gx)
    2888          626 :             IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    2889              :                CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_gx_old_im, &
    2890          562 :                                qs_ot_env(ispin)%rot_mat_gx_im)
    2891              :             END IF
    2892              :          END IF
    2893         3954 :          IF (do_ener) qs_ot_env(ispin)%ener_gx_old = qs_ot_env(ispin)%ener_gx
    2894              :       END DO
    2895              : 
    2896          602 :       nhistory = MIN(qs_ot_env(1)%diis_iter - 1, m_history)
    2897              :       ALLOCATE (alpha(MAX(1, nhistory)), rho(MAX(1, nhistory)), &
    2898         3612 :                 history_index(MAX(1, nhistory)))
    2899          602 :       gamma_rotation = 1.0_dp
    2900          602 :       yy_newest = 0.0_dp
    2901              : 
    2902              :       ! First loop, newest to oldest: q <- V^T g.
    2903          602 :       IF (nhistory > 0) THEN
    2904          468 :          newest = MOD(qs_ot_env(1)%diis_iter - 2, m_history) + 1
    2905          468 :          yy_newest = qs_ot_env(1)%lbfgs_yy(newest)
    2906              :          IF (qs_ot_env(1)%settings%do_rotation .AND. &
    2907              :              ieee_is_finite(qs_ot_env(1)%lbfgs_sy_rotation(newest)) .AND. &
    2908              :              ieee_is_finite(qs_ot_env(1)%lbfgs_yy_rotation(newest)) .AND. &
    2909          468 :              qs_ot_env(1)%lbfgs_sy_rotation(newest) > 0.0_dp .AND. &
    2910              :              qs_ot_env(1)%lbfgs_yy_rotation(newest) > 0.0_dp) THEN
    2911              :             gamma_rotation = MAX(rotation_scale_min, MIN(rotation_scale_max, &
    2912              :                                                          qs_ot_env(1)%lbfgs_sy_rotation(newest)/ &
    2913          318 :                                                          qs_ot_env(1)%lbfgs_yy_rotation(newest)))
    2914              :          END IF
    2915         2590 :          DO i = 1, nhistory
    2916         2122 :             history_index(i) = MODULO(newest - i, m_history) + 1
    2917         2122 :             stq = 0.0_dp
    2918         5058 :             DO ispin = 1, nspin
    2919              :                CALL dbcsr_dot(qs_ot_env(ispin)%matrix_h_x(history_index(i))%matrix, &
    2920         2936 :                               qs_ot_env(ispin)%matrix_gx_old, tmp)
    2921         2936 :                stq = stq + tmp
    2922         2936 :                IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    2923              :                   CALL dbcsr_dot(qs_ot_env(ispin)%matrix_h_x_im(history_index(i))%matrix, &
    2924         2246 :                                  qs_ot_env(ispin)%matrix_gx_old_im, tmp)
    2925         2246 :                   stq = stq + tmp
    2926              :                END IF
    2927         2936 :                IF (qs_ot_env(1)%settings%do_rotation) THEN
    2928              :                   CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_h_x(history_index(i))%matrix, &
    2929         2486 :                                  qs_ot_env(ispin)%rot_mat_gx_old, tmp)
    2930         2486 :                   stq = stq + 0.5_dp*tmp
    2931         2486 :                   IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    2932              :                      CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_h_x_im(history_index(i))%matrix, &
    2933         2150 :                                     qs_ot_env(ispin)%rot_mat_gx_old_im, tmp)
    2934         2150 :                      stq = stq + 0.5_dp*tmp
    2935              :                   END IF
    2936              :                END IF
    2937         7994 :                IF (do_ener) THEN
    2938              :                   stq = stq + DOT_PRODUCT(qs_ot_env(ispin)%ener_h_x(history_index(i), :), &
    2939        13104 :                                           qs_ot_env(ispin)%ener_gx_old)
    2940              :                END IF
    2941              :             END DO
    2942         2122 :             CALL ot_mini_sum_kpoint_scalar(para_env_inter_kp, stq)
    2943         2122 :             rho(i) = qs_ot_env(1)%lbfgs_rho(history_index(i))
    2944         2122 :             alpha(i) = rho(i)*stq
    2945         5526 :             DO ispin = 1, nspin
    2946              :                CALL dbcsr_add(qs_ot_env(ispin)%matrix_gx_old, &
    2947              :                               qs_ot_env(ispin)%matrix_h_e(history_index(i))%matrix, &
    2948         2936 :                               alpha_scalar=1.0_dp, beta_scalar=-alpha(i))
    2949         2936 :                IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    2950              :                   CALL dbcsr_add(qs_ot_env(ispin)%matrix_gx_old_im, &
    2951              :                                  qs_ot_env(ispin)%matrix_h_e_im(history_index(i))%matrix, &
    2952         2246 :                                  alpha_scalar=1.0_dp, beta_scalar=-alpha(i))
    2953              :                END IF
    2954         2936 :                IF (qs_ot_env(1)%settings%do_rotation) THEN
    2955              :                   CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_gx_old, &
    2956              :                                  qs_ot_env(ispin)%rot_mat_h_e(history_index(i))%matrix, &
    2957         2486 :                                  alpha_scalar=1.0_dp, beta_scalar=-alpha(i))
    2958         2486 :                   IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    2959              :                      CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_gx_old_im, &
    2960              :                                     qs_ot_env(ispin)%rot_mat_h_e_im(history_index(i))%matrix, &
    2961         2150 :                                     alpha_scalar=1.0_dp, beta_scalar=-alpha(i))
    2962              :                   END IF
    2963              :                END IF
    2964         5058 :                IF (do_ener) THEN
    2965              :                   qs_ot_env(ispin)%ener_gx_old = qs_ot_env(ispin)%ener_gx_old - &
    2966        13104 :                                                  alpha(i)*qs_ot_env(ispin)%ener_h_e(history_index(i), :)
    2967              :                END IF
    2968              :             END DO
    2969              :          END DO
    2970              :       END IF
    2971              : 
    2972              :       ! Apply the conventional initial inverse Hessian and, when requested, its positive linear
    2973              :       ! occupation-response completion to the arbitrary vector from the first loop.
    2974          134 :       gamma = 1.0_dp
    2975          468 :       IF (nhistory > 0 .AND. yy_newest > 0.0_dp) gamma = 1.0_dp/(rho(1)*yy_newest)
    2976              :       CALL ot_apply_lbfgs_initial_inverse( &
    2977          602 :          qs_ot_env, gamma, gamma_rotation, m_history + 1, para_env_inter_kp)
    2978              : 
    2979              :       ! The m+1 slot was scratch space for the occupation secant completion. Preserve the current
    2980              :       ! accepted point and physical gradient there for the next L-BFGS update.
    2981         1462 :       DO ispin = 1, nspin
    2982              :          CALL dbcsr_copy(qs_ot_env(ispin)%matrix_h_x(m_history + 1)%matrix, &
    2983          860 :                          qs_ot_env(ispin)%matrix_x)
    2984              :          CALL dbcsr_copy(qs_ot_env(ispin)%matrix_h_e(m_history + 1)%matrix, &
    2985          860 :                          qs_ot_env(ispin)%matrix_gx)
    2986          860 :          IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    2987              :             CALL dbcsr_copy(qs_ot_env(ispin)%matrix_h_x_im(m_history + 1)%matrix, &
    2988          690 :                             qs_ot_env(ispin)%matrix_x_im)
    2989              :             CALL dbcsr_copy(qs_ot_env(ispin)%matrix_h_e_im(m_history + 1)%matrix, &
    2990          690 :                             qs_ot_env(ispin)%matrix_gx_im)
    2991              :          END IF
    2992          860 :          IF (qs_ot_env(1)%settings%do_rotation) THEN
    2993              :             CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_h_x(m_history + 1)%matrix, &
    2994          626 :                             qs_ot_env(ispin)%rot_mat_x)
    2995              :             CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_h_e(m_history + 1)%matrix, &
    2996          626 :                             qs_ot_env(ispin)%rot_mat_gx)
    2997          626 :             IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    2998              :                CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_h_x_im(m_history + 1)%matrix, &
    2999          562 :                                qs_ot_env(ispin)%rot_mat_x_im)
    3000              :                CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_h_e_im(m_history + 1)%matrix, &
    3001          562 :                                qs_ot_env(ispin)%rot_mat_gx_im)
    3002              :             END IF
    3003              :          END IF
    3004         1462 :          IF (do_ener) THEN
    3005         2726 :             qs_ot_env(ispin)%ener_h_x(m_history + 1, :) = qs_ot_env(ispin)%ener_x
    3006         2726 :             qs_ot_env(ispin)%ener_h_e(m_history + 1, :) = qs_ot_env(ispin)%ener_gx
    3007              :          END IF
    3008              :       END DO
    3009              : 
    3010              :       ! Second loop, oldest to newest: z <- V H0 V^T g.
    3011         2724 :       DO i = nhistory, 1, -1
    3012         2122 :          beta = 0.0_dp
    3013         5058 :          DO ispin = 1, nspin
    3014              :             CALL dbcsr_dot(qs_ot_env(ispin)%matrix_h_e(history_index(i))%matrix, &
    3015         2936 :                            qs_ot_env(ispin)%matrix_dx, tmp)
    3016         2936 :             beta = beta + tmp
    3017         2936 :             IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    3018              :                CALL dbcsr_dot(qs_ot_env(ispin)%matrix_h_e_im(history_index(i))%matrix, &
    3019         2246 :                               qs_ot_env(ispin)%matrix_dx_im, tmp)
    3020         2246 :                beta = beta + tmp
    3021              :             END IF
    3022         2936 :             IF (qs_ot_env(1)%settings%do_rotation) THEN
    3023              :                CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_h_e(history_index(i))%matrix, &
    3024         2486 :                               qs_ot_env(ispin)%rot_mat_dx, tmp)
    3025         2486 :                beta = beta + 0.5_dp*tmp
    3026         2486 :                IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    3027              :                   CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_h_e_im(history_index(i))%matrix, &
    3028         2150 :                                  qs_ot_env(ispin)%rot_mat_dx_im, tmp)
    3029         2150 :                   beta = beta + 0.5_dp*tmp
    3030              :                END IF
    3031              :             END IF
    3032         7994 :             IF (do_ener) THEN
    3033              :                beta = beta + DOT_PRODUCT(qs_ot_env(ispin)%ener_h_e(history_index(i), :), &
    3034        13104 :                                          qs_ot_env(ispin)%ener_dx)
    3035              :             END IF
    3036              :          END DO
    3037         2122 :          CALL ot_mini_sum_kpoint_scalar(para_env_inter_kp, beta)
    3038         2122 :          beta = rho(i)*beta
    3039         5660 :          DO ispin = 1, nspin
    3040              :             CALL dbcsr_add(qs_ot_env(ispin)%matrix_dx, &
    3041              :                            qs_ot_env(ispin)%matrix_h_x(history_index(i))%matrix, &
    3042         2936 :                            alpha_scalar=1.0_dp, beta_scalar=alpha(i) - beta)
    3043         2936 :             IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    3044              :                CALL dbcsr_add(qs_ot_env(ispin)%matrix_dx_im, &
    3045              :                               qs_ot_env(ispin)%matrix_h_x_im(history_index(i))%matrix, &
    3046         2246 :                               alpha_scalar=1.0_dp, beta_scalar=alpha(i) - beta)
    3047              :             END IF
    3048         2936 :             IF (qs_ot_env(1)%settings%do_rotation) THEN
    3049              :                CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_dx, &
    3050              :                               qs_ot_env(ispin)%rot_mat_h_x(history_index(i))%matrix, &
    3051         2486 :                               alpha_scalar=1.0_dp, beta_scalar=alpha(i) - beta)
    3052         2486 :                IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    3053              :                   CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_dx_im, &
    3054              :                                  qs_ot_env(ispin)%rot_mat_h_x_im(history_index(i))%matrix, &
    3055         2150 :                                  alpha_scalar=1.0_dp, beta_scalar=alpha(i) - beta)
    3056              :                END IF
    3057              :             END IF
    3058         5058 :             IF (do_ener) THEN
    3059              :                qs_ot_env(ispin)%ener_dx = qs_ot_env(ispin)%ener_dx + &
    3060              :                                           (alpha(i) - beta)* &
    3061        13104 :                                           qs_ot_env(ispin)%ener_h_x(history_index(i), :)
    3062              :             END IF
    3063              :          END DO
    3064              :       END DO
    3065              : 
    3066          602 :       g_dot_z = 0.0_dp
    3067         1462 :       DO ispin = 1, nspin
    3068          860 :          CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_dx, tmp)
    3069          860 :          g_dot_z = g_dot_z + tmp
    3070          860 :          IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    3071          690 :             CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx_im, qs_ot_env(ispin)%matrix_dx_im, tmp)
    3072          690 :             g_dot_z = g_dot_z + tmp
    3073              :          END IF
    3074          860 :          IF (qs_ot_env(1)%settings%do_rotation) THEN
    3075          626 :             CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx, qs_ot_env(ispin)%rot_mat_dx, tmp)
    3076          626 :             g_dot_z = g_dot_z + 0.5_dp*tmp
    3077          626 :             IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    3078              :                CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx_im, &
    3079          562 :                               qs_ot_env(ispin)%rot_mat_dx_im, tmp)
    3080          562 :                g_dot_z = g_dot_z + 0.5_dp*tmp
    3081              :             END IF
    3082              :          END IF
    3083         2322 :          IF (do_ener) THEN
    3084              :             g_dot_z = g_dot_z + DOT_PRODUCT(qs_ot_env(ispin)%ener_gx, &
    3085         2726 :                                             qs_ot_env(ispin)%ener_dx)
    3086              :          END IF
    3087              :       END DO
    3088          602 :       CALL ot_mini_sum_kpoint_scalar(para_env_inter_kp, g_dot_z)
    3089              : 
    3090              :       ! Preserve a guaranteed descent direction even if the supplied initial preconditioner is
    3091              :       ! indefinite or numerical noise corrupts the secant recursion.
    3092          602 :       IF (.NOT. ieee_is_finite(g_dot_z) .OR. g_dot_z <= 0.0_dp) THEN
    3093            0 :          qs_ot_env(1)%diis_iter = 1
    3094            0 :          qs_ot_env(1)%OT_METHOD_FULL = "OT L-SD"
    3095            0 :          IF (ASSOCIATED(qs_ot_env(1)%preconditioner)) THEN
    3096            0 :             DO ispin = 1, nspin
    3097            0 :                IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    3098              :                   CALL apply_preconditioner(qs_ot_env(ispin)%preconditioner, &
    3099              :                                             qs_ot_env(ispin)%matrix_gx, &
    3100              :                                             qs_ot_env(ispin)%matrix_gx_im, &
    3101              :                                             qs_ot_env(ispin)%matrix_dx, &
    3102            0 :                                             qs_ot_env(ispin)%matrix_dx_im)
    3103            0 :                   CPASSERT(qs_ot_env(ispin)%kpoint_weight > 0.0_dp)
    3104            0 :                   tmp = qs_ot_kpoint_preconditioner_scale(qs_ot_env(ispin)%kpoint_weight)
    3105            0 :                   CALL dbcsr_scale(qs_ot_env(ispin)%matrix_dx, tmp)
    3106            0 :                   CALL dbcsr_scale(qs_ot_env(ispin)%matrix_dx_im, tmp)
    3107              :                ELSE
    3108              :                   CALL apply_preconditioner(qs_ot_env(ispin)%preconditioner, &
    3109            0 :                                             qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_dx)
    3110              :                END IF
    3111            0 :                IF (qs_ot_env(1)%settings%do_rotation) THEN
    3112            0 :                   CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_dx, qs_ot_env(ispin)%rot_mat_gx)
    3113            0 :                   IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    3114              :                      CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_dx_im, &
    3115            0 :                                      qs_ot_env(ispin)%rot_mat_gx_im)
    3116              :                   END IF
    3117              :                END IF
    3118            0 :                IF (do_ener) qs_ot_env(ispin)%ener_dx = qs_ot_env(ispin)%ener_gx
    3119              :             END DO
    3120              :          ELSE
    3121            0 :             DO ispin = 1, nspin
    3122            0 :                CALL dbcsr_copy(qs_ot_env(ispin)%matrix_dx, qs_ot_env(ispin)%matrix_gx)
    3123            0 :                IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    3124            0 :                   CALL dbcsr_copy(qs_ot_env(ispin)%matrix_dx_im, qs_ot_env(ispin)%matrix_gx_im)
    3125              :                END IF
    3126            0 :                IF (qs_ot_env(1)%settings%do_rotation) THEN
    3127            0 :                   CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_dx, qs_ot_env(ispin)%rot_mat_gx)
    3128            0 :                   IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    3129              :                      CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_dx_im, &
    3130            0 :                                      qs_ot_env(ispin)%rot_mat_gx_im)
    3131              :                   END IF
    3132              :                END IF
    3133            0 :                IF (do_ener) qs_ot_env(ispin)%ener_dx = qs_ot_env(ispin)%ener_gx
    3134              :             END DO
    3135              :          END IF
    3136            0 :          g_dot_z = 0.0_dp
    3137            0 :          DO ispin = 1, nspin
    3138            0 :             CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_dx, tmp)
    3139            0 :             g_dot_z = g_dot_z + tmp
    3140            0 :             IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    3141            0 :                CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx_im, qs_ot_env(ispin)%matrix_dx_im, tmp)
    3142            0 :                g_dot_z = g_dot_z + tmp
    3143              :             END IF
    3144            0 :             IF (qs_ot_env(1)%settings%do_rotation) THEN
    3145            0 :                CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx, qs_ot_env(ispin)%rot_mat_dx, tmp)
    3146            0 :                g_dot_z = g_dot_z + 0.5_dp*tmp
    3147            0 :                IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    3148              :                   CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx_im, &
    3149            0 :                                  qs_ot_env(ispin)%rot_mat_dx_im, tmp)
    3150            0 :                   g_dot_z = g_dot_z + 0.5_dp*tmp
    3151              :                END IF
    3152              :             END IF
    3153            0 :             IF (do_ener) THEN
    3154              :                g_dot_z = g_dot_z + DOT_PRODUCT(qs_ot_env(ispin)%ener_gx, &
    3155            0 :                                                qs_ot_env(ispin)%ener_dx)
    3156              :             END IF
    3157              :          END DO
    3158            0 :          CALL ot_mini_sum_kpoint_scalar(para_env_inter_kp, g_dot_z)
    3159            0 :          IF (.NOT. ieee_is_finite(g_dot_z) .OR. g_dot_z <= 0.0_dp) THEN
    3160            0 :             g_dot_z = 0.0_dp
    3161            0 :             DO ispin = 1, nspin
    3162            0 :                CALL dbcsr_copy(qs_ot_env(ispin)%matrix_dx, qs_ot_env(ispin)%matrix_gx)
    3163            0 :                CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_dx, tmp)
    3164            0 :                g_dot_z = g_dot_z + tmp
    3165            0 :                IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    3166            0 :                   CALL dbcsr_copy(qs_ot_env(ispin)%matrix_dx_im, qs_ot_env(ispin)%matrix_gx_im)
    3167              :                   CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx_im, &
    3168            0 :                                  qs_ot_env(ispin)%matrix_dx_im, tmp)
    3169            0 :                   g_dot_z = g_dot_z + tmp
    3170              :                END IF
    3171            0 :                IF (qs_ot_env(1)%settings%do_rotation) THEN
    3172            0 :                   CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_dx, qs_ot_env(ispin)%rot_mat_gx)
    3173            0 :                   CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx, qs_ot_env(ispin)%rot_mat_dx, tmp)
    3174            0 :                   g_dot_z = g_dot_z + 0.5_dp*tmp
    3175            0 :                   IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    3176              :                      CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_dx_im, &
    3177            0 :                                      qs_ot_env(ispin)%rot_mat_gx_im)
    3178              :                      CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx_im, &
    3179            0 :                                     qs_ot_env(ispin)%rot_mat_dx_im, tmp)
    3180            0 :                      g_dot_z = g_dot_z + 0.5_dp*tmp
    3181              :                   END IF
    3182              :                END IF
    3183            0 :                IF (do_ener) THEN
    3184            0 :                   qs_ot_env(ispin)%ener_dx = qs_ot_env(ispin)%ener_gx
    3185              :                   g_dot_z = g_dot_z + DOT_PRODUCT(qs_ot_env(ispin)%ener_gx, &
    3186            0 :                                                   qs_ot_env(ispin)%ener_dx)
    3187              :                END IF
    3188              :             END DO
    3189            0 :             CALL ot_mini_sum_kpoint_scalar(para_env_inter_kp, g_dot_z)
    3190              :          END IF
    3191              :       END IF
    3192              : 
    3193         1462 :       DO ispin = 1, nspin
    3194          860 :          CALL dbcsr_scale(qs_ot_env(ispin)%matrix_dx, -1.0_dp)
    3195          860 :          IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    3196          690 :             CALL dbcsr_scale(qs_ot_env(ispin)%matrix_dx_im, -1.0_dp)
    3197              :          END IF
    3198          860 :          IF (qs_ot_env(1)%settings%do_rotation) THEN
    3199          626 :             CALL dbcsr_scale(qs_ot_env(ispin)%rot_mat_dx, -1.0_dp)
    3200          626 :             IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    3201          562 :                CALL dbcsr_scale(qs_ot_env(ispin)%rot_mat_dx_im, -1.0_dp)
    3202              :             END IF
    3203              :          END IF
    3204         3954 :          IF (do_ener) qs_ot_env(ispin)%ener_dx = -qs_ot_env(ispin)%ener_dx
    3205              :       END DO
    3206          602 :       qs_ot_env(1)%gnorm = g_dot_z
    3207          602 :       qs_ot_env(1)%gradient = -g_dot_z
    3208              : 
    3209          602 :       k = 0
    3210              :       n = 0
    3211          602 :       nener = 0
    3212          602 :       nrotation = 0_int_8
    3213          602 :       CALL dbcsr_get_info(qs_ot_env(1)%matrix_x, nfullrows_total=n)
    3214         1462 :       DO ispin = 1, nspin
    3215          860 :          CALL dbcsr_get_info(qs_ot_env(ispin)%matrix_x, nfullcols_total=itmp)
    3216          860 :          k = k + itmp
    3217          860 :          IF (qs_ot_env(ispin)%has_complex_kpoint_state) k = k + itmp
    3218          860 :          IF (qs_ot_env(1)%settings%do_rotation) THEN
    3219          626 :             nrotation = nrotation + INT(itmp, KIND=int_8)*INT(itmp - 1, KIND=int_8)/2_int_8
    3220          626 :             IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    3221          562 :                nrotation = nrotation + INT(itmp, KIND=int_8)*INT(itmp + 1, KIND=int_8)/2_int_8
    3222              :             END IF
    3223              :          END IF
    3224         2322 :          IF (do_ener) nener = nener + SIZE(qs_ot_env(ispin)%ener_x)
    3225              :       END DO
    3226              :       nvariables = INT(n, KIND=int_8)*INT(k, KIND=int_8) + nrotation + &
    3227          602 :                    INT(nener, KIND=int_8)
    3228          602 :       nvariables_global = REAL(nvariables, KIND=dp)
    3229          602 :       CALL ot_mini_sum_kpoint_scalar(para_env_inter_kp, nvariables_global)
    3230          602 :       IF (nvariables_global > 0.0_dp) THEN
    3231          602 :          qs_ot_env(1)%delta = SQRT(ABS(g_dot_z)/nvariables_global)
    3232              :       ELSE
    3233            0 :          qs_ot_env(1)%delta = 0.0_dp
    3234            0 :          qs_ot_env(1)%gradient = 0.0_dp
    3235              :       END IF
    3236              : 
    3237          602 :       test_down = -g_dot_z
    3238              :       CALL ot_try_mermin_response_direction( &
    3239          602 :          qs_ot_env, para_env_inter_kp, qs_ot_env(1)%delta, test_down, use_response_candidate)
    3240          602 :       IF (use_response_candidate) THEN
    3241              :          ! A sparse finite-response probe changes the inverse model outside the accumulated
    3242              :          ! L-BFGS secant space. Restart that space while retaining the accepted point used by the
    3243              :          ! next update; this avoids mixing a calibrated physical candidate with stale curvature.
    3244            6 :          qs_ot_env(1)%diis_iter = 1
    3245            6 :          qs_ot_env(1)%OT_METHOD_FULL = "OT L-R"
    3246            6 :          qs_ot_env(1)%gnorm = -test_down
    3247            6 :          qs_ot_env(1)%gradient = test_down
    3248              :       END IF
    3249              : 
    3250          602 :       DEALLOCATE (alpha, rho, history_index)
    3251          602 :       CALL timestop(handle)
    3252              : 
    3253         1806 :    END SUBROUTINE ot_new_lbfgs_direction
    3254              : 
    3255              : ! **************************************************************************************************
    3256              : !> \brief Build a preconditioned product residual for history-based OT minimizers.
    3257              : !> \param qs_ot_env OT environments for all local spin/k-point channels
    3258              : !> \param history_index destination slot in the residual history
    3259              : !> \param step_scale scale applied after evaluating the descent product
    3260              : !> \param para_env_inter_kp communicator between distributed k-point groups
    3261              : !> \param gnorm product of the physical Mermin gradient and preconditioned residual
    3262              : ! **************************************************************************************************
    3263        50658 :    SUBROUTINE ot_build_history_residual(qs_ot_env, history_index, step_scale, &
    3264              :                                         para_env_inter_kp, gnorm)
    3265              :       TYPE(qs_ot_type), DIMENSION(:), POINTER            :: qs_ot_env
    3266              :       INTEGER, INTENT(IN)                                :: history_index
    3267              :       REAL(KIND=dp), INTENT(IN)                          :: step_scale
    3268              :       TYPE(mp_para_env_type), OPTIONAL, POINTER          :: para_env_inter_kp
    3269              :       REAL(KIND=dp), INTENT(OUT)                         :: gnorm
    3270              : 
    3271              :       LOGICAL                                            :: use_occupation_response
    3272              :       TYPE(cp_logger_type), POINTER                      :: logger
    3273              : 
    3274        50658 :       use_occupation_response = qs_ot_env(1)%settings%occupation_preconditioner
    3275              :       CALL ot_build_history_residual_once(qs_ot_env, history_index, step_scale, &
    3276        50658 :                                           use_occupation_response, gnorm)
    3277        50658 :       CALL ot_mini_sum_kpoint_scalar(para_env_inter_kp, gnorm)
    3278              : 
    3279              :       ! The occupation response is a coupled orbital/energy approximation. Falling back one block
    3280              :       ! at a time would change its Schur balance, so replace the complete product residual instead.
    3281        50658 :       IF (use_occupation_response .AND. gnorm <= 0.0_dp) THEN
    3282            6 :          CALL ot_build_history_residual_once(qs_ot_env, history_index, step_scale, .FALSE., gnorm)
    3283            6 :          CALL ot_mini_sum_kpoint_scalar(para_env_inter_kp, gnorm)
    3284              :       END IF
    3285        50658 :       IF (gnorm < 0.0_dp) THEN
    3286            0 :          logger => cp_get_default_logger()
    3287            0 :          WRITE (cp_logger_get_default_unit_nr(logger), *) "WARNING Preconditioner not positive definite !"
    3288              :       END IF
    3289        50658 :    END SUBROUTINE ot_build_history_residual
    3290              : 
    3291              : ! **************************************************************************************************
    3292              : !> \brief Build one physical or occupation-response product residual.
    3293              : !> \param qs_ot_env OT environments for all local spin/k-point channels
    3294              : !> \param history_index destination slot in the residual history
    3295              : !> \param step_scale scale applied to the stored residual
    3296              : !> \param use_occupation_response use the fixed-N occupation-response approximation
    3297              : !> \param gnorm product of the physical Mermin gradient and unscaled residual
    3298              : ! **************************************************************************************************
    3299        50664 :    SUBROUTINE ot_build_history_residual_once(qs_ot_env, history_index, step_scale, &
    3300              :                                              use_occupation_response, gnorm)
    3301              :       TYPE(qs_ot_type), DIMENSION(:), POINTER            :: qs_ot_env
    3302              :       INTEGER, INTENT(IN)                                :: history_index
    3303              :       REAL(KIND=dp), INTENT(IN)                          :: step_scale
    3304              :       LOGICAL, INTENT(IN)                                :: use_occupation_response
    3305              :       REAL(KIND=dp), INTENT(OUT)                         :: gnorm
    3306              : 
    3307              :       INTEGER                                            :: ispin
    3308              :       LOGICAL                                            :: do_ener, do_ks
    3309              :       REAL(KIND=dp)                                      :: kpoint_scale, tmp
    3310              :       TYPE(dbcsr_type), POINTER                          :: orbital_residual, orbital_residual_im
    3311              : 
    3312        50664 :       do_ks = qs_ot_env(1)%settings%ks
    3313        50664 :       do_ener = qs_ot_env(1)%settings%do_ener
    3314        50664 :       gnorm = 0.0_dp
    3315              : 
    3316        50664 :       IF (do_ks) THEN
    3317       107290 :          DO ispin = 1, SIZE(qs_ot_env)
    3318        56626 :             IF (use_occupation_response) THEN
    3319          424 :                CPASSERT(ASSOCIATED(qs_ot_env(ispin)%matrix_preconditioned_gx))
    3320          424 :                orbital_residual => qs_ot_env(ispin)%matrix_preconditioned_gx
    3321          424 :                IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    3322          424 :                   CPASSERT(ASSOCIATED(qs_ot_env(ispin)%matrix_preconditioned_gx_im))
    3323          424 :                   orbital_residual_im => qs_ot_env(ispin)%matrix_preconditioned_gx_im
    3324              :                END IF
    3325              :             ELSE
    3326        56202 :                orbital_residual => qs_ot_env(ispin)%matrix_gx
    3327        56202 :                IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    3328         1140 :                   orbital_residual_im => qs_ot_env(ispin)%matrix_gx_im
    3329              :                END IF
    3330              :             END IF
    3331              : 
    3332        56626 :             IF (ASSOCIATED(qs_ot_env(1)%preconditioner)) THEN
    3333        51662 :                IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    3334              :                   CALL apply_preconditioner(qs_ot_env(ispin)%preconditioner, &
    3335              :                                             orbital_residual, orbital_residual_im, &
    3336              :                                             qs_ot_env(ispin)%matrix_h_e(history_index)%matrix, &
    3337         1516 :                                             qs_ot_env(ispin)%matrix_h_e_im(history_index)%matrix)
    3338         1516 :                   CPASSERT(qs_ot_env(ispin)%kpoint_weight > 0.0_dp)
    3339         1516 :                   kpoint_scale = qs_ot_kpoint_preconditioner_scale(qs_ot_env(ispin)%kpoint_weight)
    3340         1516 :                   CALL dbcsr_scale(qs_ot_env(ispin)%matrix_h_e(history_index)%matrix, kpoint_scale)
    3341         1516 :                   CALL dbcsr_scale(qs_ot_env(ispin)%matrix_h_e_im(history_index)%matrix, kpoint_scale)
    3342              :                ELSE
    3343              :                   CALL apply_preconditioner(qs_ot_env(ispin)%preconditioner, orbital_residual, &
    3344        50146 :                                             qs_ot_env(ispin)%matrix_h_e(history_index)%matrix)
    3345              :                END IF
    3346              :             ELSE
    3347         4964 :                CALL dbcsr_copy(qs_ot_env(ispin)%matrix_h_e(history_index)%matrix, orbital_residual)
    3348         4964 :                IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    3349              :                   CALL dbcsr_copy(qs_ot_env(ispin)%matrix_h_e_im(history_index)%matrix, &
    3350           48 :                                   orbital_residual_im)
    3351              :                END IF
    3352              :             END IF
    3353              : 
    3354              :             CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, &
    3355        56626 :                            qs_ot_env(ispin)%matrix_h_e(history_index)%matrix, tmp)
    3356        56626 :             gnorm = gnorm + tmp
    3357        56626 :             CALL dbcsr_scale(qs_ot_env(ispin)%matrix_h_e(history_index)%matrix, step_scale)
    3358        56626 :             IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    3359              :                CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx_im, &
    3360         1564 :                               qs_ot_env(ispin)%matrix_h_e_im(history_index)%matrix, tmp)
    3361         1564 :                gnorm = gnorm + tmp
    3362         1564 :                CALL dbcsr_scale(qs_ot_env(ispin)%matrix_h_e_im(history_index)%matrix, step_scale)
    3363              :             END IF
    3364              : 
    3365       163916 :             IF (qs_ot_env(ispin)%settings%do_rotation) THEN
    3366              :                CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_h_e(history_index)%matrix, &
    3367          866 :                                qs_ot_env(ispin)%rot_mat_gx)
    3368              :                CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx, &
    3369          866 :                               qs_ot_env(ispin)%rot_mat_h_e(history_index)%matrix, tmp)
    3370          866 :                gnorm = gnorm + 0.5_dp*tmp
    3371          866 :                CALL dbcsr_scale(qs_ot_env(ispin)%rot_mat_h_e(history_index)%matrix, step_scale)
    3372          866 :                IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    3373              :                   CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_h_e_im(history_index)%matrix, &
    3374          500 :                                   qs_ot_env(ispin)%rot_mat_gx_im)
    3375              :                   CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx_im, &
    3376          500 :                                  qs_ot_env(ispin)%rot_mat_h_e_im(history_index)%matrix, tmp)
    3377          500 :                   gnorm = gnorm + 0.5_dp*tmp
    3378          500 :                   CALL dbcsr_scale(qs_ot_env(ispin)%rot_mat_h_e_im(history_index)%matrix, step_scale)
    3379              :                END IF
    3380              :             END IF
    3381              :          END DO
    3382              :       END IF
    3383              : 
    3384        50664 :       IF (do_ener) THEN
    3385          810 :          DO ispin = 1, SIZE(qs_ot_env)
    3386          436 :             IF (use_occupation_response) THEN
    3387          424 :                CPASSERT(ASSOCIATED(qs_ot_env(ispin)%ener_preconditioned_gx))
    3388              :                qs_ot_env(ispin)%ener_h_e(history_index, :) = &
    3389         3664 :                   qs_ot_env(ispin)%ener_preconditioned_gx
    3390              :             ELSE
    3391           48 :                qs_ot_env(ispin)%ener_h_e(history_index, :) = qs_ot_env(ispin)%ener_gx
    3392              :             END IF
    3393              :             gnorm = gnorm + DOT_PRODUCT(qs_ot_env(ispin)%ener_gx, &
    3394         3712 :                                         qs_ot_env(ispin)%ener_h_e(history_index, :))
    3395              :             qs_ot_env(ispin)%ener_h_e(history_index, :) = &
    3396         4086 :                step_scale*qs_ot_env(ispin)%ener_h_e(history_index, :)
    3397              :          END DO
    3398              :       END IF
    3399        50664 :    END SUBROUTINE ot_build_history_residual_once
    3400              : 
    3401              : ! **************************************************************************************************
    3402              : !> \brief ...
    3403              : !> \param qs_ot_env ...
    3404              : !> \param para_env_inter_kp communicator between distributed k-point groups
    3405              : ! **************************************************************************************************
    3406        50452 :    SUBROUTINE ot_diis_step(qs_ot_env, para_env_inter_kp)
    3407              :       TYPE(qs_ot_type), DIMENSION(:), POINTER            :: qs_ot_env
    3408              :       TYPE(mp_para_env_type), OPTIONAL, POINTER          :: para_env_inter_kp
    3409              : 
    3410              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'ot_diis_step'
    3411              : 
    3412              :       INTEGER                                            :: diis_bound, diis_m, handle, i, info, &
    3413              :                                                             ispin, itmp, j, k, n, nener, nspin
    3414              :       LOGICAL                                            :: do_ener, do_ks, do_ot_sd
    3415              :       REAL(KIND=dp)                                      :: nvariables, overlap, tmp, tr_xnew_gx, &
    3416              :                                                             tr_xold_gx
    3417              :       TYPE(cp_logger_type), POINTER                      :: logger
    3418              : 
    3419        50452 :       CALL timeset(routineN, handle)
    3420              : 
    3421        50452 :       logger => cp_get_default_logger()
    3422              : 
    3423        50452 :       do_ks = qs_ot_env(1)%settings%ks
    3424        50452 :       do_ener = qs_ot_env(1)%settings%do_ener
    3425        50452 :       nspin = SIZE(qs_ot_env)
    3426              : 
    3427        50452 :       diis_m = qs_ot_env(1)%settings%diis_m
    3428              : 
    3429        50452 :       IF (qs_ot_env(1)%diis_iter < diis_m) THEN
    3430        30461 :          diis_bound = qs_ot_env(1)%diis_iter + 1
    3431              :       ELSE
    3432              :          diis_bound = diis_m
    3433              :       END IF
    3434              : 
    3435        50452 :       j = MOD(qs_ot_env(1)%diis_iter, diis_m) + 1 ! index in the circular array
    3436              : 
    3437              :       ! copy the position and the error vector in the diis buffers
    3438              : 
    3439        50452 :       IF (do_ks) THEN
    3440       106832 :          DO ispin = 1, nspin
    3441        56380 :             CALL dbcsr_copy(qs_ot_env(ispin)%matrix_h_x(j)%matrix, qs_ot_env(ispin)%matrix_x)
    3442        56380 :             IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    3443              :                CALL dbcsr_copy(qs_ot_env(ispin)%matrix_h_x_im(j)%matrix, &
    3444         1496 :                                qs_ot_env(ispin)%matrix_x_im)
    3445              :             END IF
    3446       106832 :             IF (qs_ot_env(ispin)%settings%do_rotation) THEN
    3447          798 :                CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_h_x(j)%matrix, qs_ot_env(ispin)%rot_mat_x)
    3448          798 :                IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    3449              :                   CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_h_x_im(j)%matrix, &
    3450          432 :                                   qs_ot_env(ispin)%rot_mat_x_im)
    3451              :                END IF
    3452              :             END IF
    3453              :          END DO
    3454              :       END IF
    3455        50452 :       IF (do_ener) THEN
    3456          708 :          DO ispin = 1, nspin
    3457         3780 :             qs_ot_env(ispin)%ener_h_x(j, :) = qs_ot_env(ispin)%ener_x(:)
    3458              :          END DO
    3459              :       END IF
    3460              :       CALL ot_build_history_residual(qs_ot_env, j, -qs_ot_env(1)%ds_min, &
    3461        50452 :                                      para_env_inter_kp, qs_ot_env(1)%gnorm)
    3462        50452 :       k = 0
    3463        50452 :       n = 0
    3464        50452 :       nener = 0
    3465        50452 :       IF (do_ks) THEN
    3466        50452 :          CALL dbcsr_get_info(qs_ot_env(1)%matrix_x, nfullrows_total=n)
    3467       106832 :          DO ispin = 1, nspin
    3468        56380 :             CALL dbcsr_get_info(qs_ot_env(ispin)%matrix_x, nfullcols_total=itmp)
    3469        56380 :             k = k + itmp
    3470       106832 :             IF (qs_ot_env(ispin)%has_complex_kpoint_state) k = k + itmp
    3471              :          END DO
    3472              :       END IF
    3473        50452 :       IF (do_ener) THEN
    3474          708 :          DO ispin = 1, nspin
    3475          708 :             nener = nener + SIZE(qs_ot_env(ispin)%ener_x)
    3476              :          END DO
    3477              :       END IF
    3478        50452 :       nvariables = REAL(INT(n, KIND=int_8)*INT(k, KIND=int_8) + nener, KIND=dp)
    3479        50452 :       CALL ot_mini_sum_kpoint_scalar(para_env_inter_kp, nvariables)
    3480              :       ! Handling the case of no free variables to optimize
    3481        50452 :       IF (nvariables > 0.0_dp) THEN
    3482        50426 :          qs_ot_env(1)%delta = SQRT(ABS(qs_ot_env(1)%gnorm)/nvariables)
    3483        50426 :          qs_ot_env(1)%gradient = -qs_ot_env(1)%gnorm
    3484              :       ELSE
    3485           26 :          qs_ot_env(1)%delta = 0.0_dp
    3486           26 :          qs_ot_env(1)%gradient = 0.0_dp
    3487              :       END IF
    3488              : 
    3489              :       ! make the diis matrix and solve it
    3490       301036 :       DO i = 1, diis_bound
    3491              :          ! I think there are two possible options, with and without preconditioner
    3492              :          ! as a metric
    3493              :          ! the second option seems most logical to me, and it seems marginally faster
    3494              :          ! in some of the tests
    3495              :          IF (.FALSE.) THEN
    3496              :             qs_ot_env(1)%ls_diis(i, j) = 0.0_dp
    3497              :             IF (do_ks) THEN
    3498              :                DO ispin = 1, nspin
    3499              :                   CALL dbcsr_dot(qs_ot_env(ispin)%matrix_h_e(j)%matrix, &
    3500              :                                  qs_ot_env(ispin)%matrix_h_e(i)%matrix, &
    3501              :                                  tmp)
    3502              :                   qs_ot_env(1)%ls_diis(i, j) = qs_ot_env(1)%ls_diis(i, j) + tmp
    3503              :                   IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    3504              :                      CALL dbcsr_dot(qs_ot_env(ispin)%matrix_h_e_im(j)%matrix, &
    3505              :                                     qs_ot_env(ispin)%matrix_h_e_im(i)%matrix, tmp)
    3506              :                      qs_ot_env(1)%ls_diis(i, j) = qs_ot_env(1)%ls_diis(i, j) + tmp
    3507              :                   END IF
    3508              :                   IF (qs_ot_env(ispin)%settings%do_rotation) THEN
    3509              :                      CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_h_e(j)%matrix, &
    3510              :                                     qs_ot_env(ispin)%rot_mat_h_e(i)%matrix, &
    3511              :                                     tmp)
    3512              :                      qs_ot_env(1)%ls_diis(i, j) = qs_ot_env(1)%ls_diis(i, j) + 0.5_dp*tmp
    3513              :                      IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    3514              :                         CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_h_e_im(j)%matrix, &
    3515              :                                        qs_ot_env(ispin)%rot_mat_h_e_im(i)%matrix, tmp)
    3516              :                         qs_ot_env(1)%ls_diis(i, j) = qs_ot_env(1)%ls_diis(i, j) + 0.5_dp*tmp
    3517              :                      END IF
    3518              :                   END IF
    3519              :                END DO
    3520              :             END IF
    3521              :             IF (do_ener) THEN
    3522              :                DO ispin = 1, nspin
    3523              :                   tmp = DOT_PRODUCT(qs_ot_env(ispin)%ener_h_e(j, :), qs_ot_env(ispin)%ener_h_e(i, :))
    3524              :                   qs_ot_env(1)%ls_diis(i, j) = qs_ot_env(1)%ls_diis(i, j) + tmp
    3525              :                END DO
    3526              :             END IF
    3527              :          ELSE
    3528       250584 :             qs_ot_env(1)%ls_diis(i, j) = 0.0_dp
    3529       250584 :             IF (do_ks) THEN
    3530       528288 :                DO ispin = 1, nspin
    3531              :                   CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, &
    3532              :                                  qs_ot_env(ispin)%matrix_h_e(i)%matrix, &
    3533       277704 :                                  tmp)
    3534       277704 :                   qs_ot_env(1)%ls_diis(i, j) = qs_ot_env(1)%ls_diis(i, j) - qs_ot_env(1)%ds_min*tmp
    3535       277704 :                   IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    3536              :                      CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx_im, &
    3537         7893 :                                     qs_ot_env(ispin)%matrix_h_e_im(i)%matrix, tmp)
    3538         7893 :                      qs_ot_env(1)%ls_diis(i, j) = qs_ot_env(1)%ls_diis(i, j) - qs_ot_env(1)%ds_min*tmp
    3539              :                   END IF
    3540       805992 :                   IF (qs_ot_env(ispin)%settings%do_rotation) THEN
    3541              :                      CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx, &
    3542              :                                     qs_ot_env(ispin)%rot_mat_h_e(i)%matrix, &
    3543         3970 :                                     tmp)
    3544         3970 :                      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
    3545         3970 :                      IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    3546              :                         CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx_im, &
    3547         1994 :                                        qs_ot_env(ispin)%rot_mat_h_e_im(i)%matrix, tmp)
    3548              :                         qs_ot_env(1)%ls_diis(i, j) = qs_ot_env(1)%ls_diis(i, j) - &
    3549         1994 :                                                      qs_ot_env(1)%ds_min*0.5_dp*tmp
    3550              :                      END IF
    3551              :                   END IF
    3552              :                END DO
    3553              :             END IF
    3554       250584 :             IF (do_ener) THEN
    3555         3538 :                DO ispin = 1, nspin
    3556        16906 :                   tmp = DOT_PRODUCT(qs_ot_env(ispin)%ener_gx(:), qs_ot_env(ispin)%ener_h_e(i, :))
    3557         3538 :                   qs_ot_env(1)%ls_diis(i, j) = qs_ot_env(1)%ls_diis(i, j) - qs_ot_env(1)%ds_min*tmp
    3558              :                END DO
    3559              :             END IF
    3560              :          END IF
    3561       250584 :          CALL ot_mini_sum_kpoint_scalar(para_env_inter_kp, qs_ot_env(1)%ls_diis(i, j))
    3562       250584 :          qs_ot_env(1)%ls_diis(j, i) = qs_ot_env(1)%ls_diis(i, j)
    3563       250584 :          qs_ot_env(1)%ls_diis(i, diis_bound + 1) = 1.0_dp
    3564       250584 :          qs_ot_env(1)%ls_diis(diis_bound + 1, i) = 1.0_dp
    3565       301036 :          qs_ot_env(1)%c_diis(i) = 0.0_dp
    3566              :       END DO
    3567        50452 :       qs_ot_env(1)%ls_diis(diis_bound + 1, diis_bound + 1) = 0.0_dp
    3568        50452 :       qs_ot_env(1)%c_diis(diis_bound + 1) = 1.0_dp
    3569              :       ! put in buffer, dgesv destroys
    3570      3719344 :       qs_ot_env(1)%lss_diis = qs_ot_env(1)%ls_diis
    3571              : 
    3572              :       CALL DGESV(diis_bound + 1, 1, qs_ot_env(1)%lss_diis, diis_m + 1, qs_ot_env(1)%ipivot, &
    3573        50452 :                  qs_ot_env(1)%c_diis, diis_m + 1, info)
    3574              : 
    3575        50452 :       IF (info /= 0) THEN
    3576            2 :          do_ot_sd = .TRUE.
    3577            2 :          WRITE (cp_logger_get_default_unit_nr(logger), *) "Singular DIIS matrix"
    3578              :       ELSE
    3579        50450 :          do_ot_sd = .FALSE.
    3580        50450 :          IF (do_ks) THEN
    3581       106828 :             DO ispin = 1, nspin
    3582              :                ! OK, add the vectors now
    3583        56378 :                CALL dbcsr_set(qs_ot_env(ispin)%matrix_x, 0.0_dp)
    3584       334068 :                DO i = 1, diis_bound
    3585              :                   CALL dbcsr_add(qs_ot_env(ispin)%matrix_x, &
    3586              :                                  qs_ot_env(ispin)%matrix_h_e(i)%matrix, &
    3587       334068 :                                  alpha_scalar=1.0_dp, beta_scalar=qs_ot_env(1)%c_diis(i))
    3588              :                END DO
    3589       334068 :                DO i = 1, diis_bound
    3590              :                   CALL dbcsr_add(qs_ot_env(ispin)%matrix_x, &
    3591              :                                  qs_ot_env(ispin)%matrix_h_x(i)%matrix, &
    3592       334068 :                                  alpha_scalar=1.0_dp, beta_scalar=qs_ot_env(1)%c_diis(i))
    3593              :                END DO
    3594        56378 :                IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    3595         1496 :                   CALL dbcsr_set(qs_ot_env(ispin)%matrix_x_im, 0.0_dp)
    3596         9389 :                   DO i = 1, diis_bound
    3597              :                      CALL dbcsr_add(qs_ot_env(ispin)%matrix_x_im, &
    3598              :                                     qs_ot_env(ispin)%matrix_h_e_im(i)%matrix, &
    3599         9389 :                                     alpha_scalar=1.0_dp, beta_scalar=qs_ot_env(1)%c_diis(i))
    3600              :                   END DO
    3601         9389 :                   DO i = 1, diis_bound
    3602              :                      CALL dbcsr_add(qs_ot_env(ispin)%matrix_x_im, &
    3603              :                                     qs_ot_env(ispin)%matrix_h_x_im(i)%matrix, &
    3604         9389 :                                     alpha_scalar=1.0_dp, beta_scalar=qs_ot_env(1)%c_diis(i))
    3605              :                   END DO
    3606              :                END IF
    3607       106828 :                IF (qs_ot_env(ispin)%settings%do_rotation) THEN
    3608          798 :                   CALL dbcsr_set(qs_ot_env(ispin)%rot_mat_x, 0.0_dp)
    3609          798 :                   IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    3610          432 :                      CALL dbcsr_set(qs_ot_env(ispin)%rot_mat_x_im, 0.0_dp)
    3611              :                   END IF
    3612         4768 :                   DO i = 1, diis_bound
    3613              :                      CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_x, &
    3614              :                                     qs_ot_env(ispin)%rot_mat_h_e(i)%matrix, &
    3615         3970 :                                     alpha_scalar=1.0_dp, beta_scalar=qs_ot_env(1)%c_diis(i))
    3616         4768 :                      IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    3617              :                         CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_x_im, &
    3618              :                                        qs_ot_env(ispin)%rot_mat_h_e_im(i)%matrix, &
    3619         1994 :                                        alpha_scalar=1.0_dp, beta_scalar=qs_ot_env(1)%c_diis(i))
    3620              :                      END IF
    3621              :                   END DO
    3622         4768 :                   DO i = 1, diis_bound
    3623              :                      CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_x, &
    3624              :                                     qs_ot_env(ispin)%rot_mat_h_x(i)%matrix, &
    3625         3970 :                                     alpha_scalar=1.0_dp, beta_scalar=qs_ot_env(1)%c_diis(i))
    3626         4768 :                      IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    3627              :                         CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_x_im, &
    3628              :                                        qs_ot_env(ispin)%rot_mat_h_x_im(i)%matrix, &
    3629         1994 :                                        alpha_scalar=1.0_dp, beta_scalar=qs_ot_env(1)%c_diis(i))
    3630              :                      END IF
    3631              :                   END DO
    3632              :                END IF
    3633              :             END DO
    3634              :          END IF
    3635        50450 :          IF (do_ener) THEN
    3636          708 :             DO ispin = 1, nspin
    3637         3440 :                qs_ot_env(ispin)%ener_x(:) = 0.0_dp
    3638         2194 :                DO i = 1, diis_bound
    3639              :                   qs_ot_env(ispin)%ener_x(:) = qs_ot_env(ispin)%ener_x(:) &
    3640        17274 :                                                + qs_ot_env(1)%c_diis(i)*qs_ot_env(ispin)%ener_h_e(i, :)
    3641              :                END DO
    3642         2534 :                DO i = 1, diis_bound
    3643              :                   qs_ot_env(ispin)%ener_x(:) = qs_ot_env(ispin)%ener_x(:) &
    3644        17274 :                                                + qs_ot_env(1)%c_diis(i)*qs_ot_env(ispin)%ener_h_x(i, :)
    3645              :                END DO
    3646              :             END DO
    3647              :          END IF
    3648        50450 :          qs_ot_env(1)%diis_iter = qs_ot_env(1)%diis_iter + 1
    3649        50450 :          IF (qs_ot_env(1)%settings%safer_diis) THEN
    3650              :             ! now, final check, is the step in fact in the direction of the -gradient ?
    3651              :             ! if not we're walking towards a sadle point, and should avoid that
    3652              :             ! the direction of the step is x_new-x_old
    3653        50450 :             tr_xold_gx = 0.0_dp
    3654        50450 :             tr_xnew_gx = 0.0_dp
    3655        50450 :             IF (do_ks) THEN
    3656       106828 :                DO ispin = 1, nspin
    3657              :                   CALL dbcsr_dot(qs_ot_env(ispin)%matrix_h_x(j)%matrix, &
    3658        56378 :                                  qs_ot_env(ispin)%matrix_gx, tmp)
    3659        56378 :                   tr_xold_gx = tr_xold_gx + tmp
    3660              :                   CALL dbcsr_dot(qs_ot_env(ispin)%matrix_x, &
    3661        56378 :                                  qs_ot_env(ispin)%matrix_gx, tmp)
    3662        56378 :                   tr_xnew_gx = tr_xnew_gx + tmp
    3663        56378 :                   IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    3664              :                      CALL dbcsr_dot(qs_ot_env(ispin)%matrix_h_x_im(j)%matrix, &
    3665         1496 :                                     qs_ot_env(ispin)%matrix_gx_im, tmp)
    3666         1496 :                      tr_xold_gx = tr_xold_gx + tmp
    3667              :                      CALL dbcsr_dot(qs_ot_env(ispin)%matrix_x_im, &
    3668         1496 :                                     qs_ot_env(ispin)%matrix_gx_im, tmp)
    3669         1496 :                      tr_xnew_gx = tr_xnew_gx + tmp
    3670              :                   END IF
    3671       163206 :                   IF (qs_ot_env(ispin)%settings%do_rotation) THEN
    3672              :                      CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_h_x(j)%matrix, &
    3673          798 :                                     qs_ot_env(ispin)%rot_mat_gx, tmp)
    3674          798 :                      tr_xold_gx = tr_xold_gx + 0.5_dp*tmp
    3675              :                      CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_x, &
    3676          798 :                                     qs_ot_env(ispin)%rot_mat_gx, tmp)
    3677          798 :                      tr_xnew_gx = tr_xnew_gx + 0.5_dp*tmp
    3678          798 :                      IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    3679              :                         CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_h_x_im(j)%matrix, &
    3680          432 :                                        qs_ot_env(ispin)%rot_mat_gx_im, tmp)
    3681          432 :                         tr_xold_gx = tr_xold_gx + 0.5_dp*tmp
    3682              :                         CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_x_im, &
    3683          432 :                                        qs_ot_env(ispin)%rot_mat_gx_im, tmp)
    3684          432 :                         tr_xnew_gx = tr_xnew_gx + 0.5_dp*tmp
    3685              :                      END IF
    3686              :                   END IF
    3687              :                END DO
    3688              :             END IF
    3689        50450 :             IF (do_ener) THEN
    3690          708 :                DO ispin = 1, nspin
    3691         3440 :                   tmp = DOT_PRODUCT(qs_ot_env(ispin)%ener_h_x(j, :), qs_ot_env(ispin)%ener_gx(:))
    3692          368 :                   tr_xold_gx = tr_xold_gx + tmp
    3693         3440 :                   tmp = DOT_PRODUCT(qs_ot_env(ispin)%ener_x(:), qs_ot_env(ispin)%ener_gx(:))
    3694          708 :                   tr_xnew_gx = tr_xnew_gx + tmp
    3695              :                END DO
    3696              :             END IF
    3697        50450 :             CALL ot_mini_sum_kpoint_scalar(para_env_inter_kp, tr_xold_gx)
    3698        50450 :             CALL ot_mini_sum_kpoint_scalar(para_env_inter_kp, tr_xnew_gx)
    3699        50450 :             overlap = (tr_xnew_gx - tr_xold_gx)
    3700              :             ! OK, bad luck, take a SD step along the preconditioned gradient
    3701        50450 :             IF (overlap > 0.0_dp) THEN
    3702              :                do_ot_sd = .TRUE.
    3703              :             END IF
    3704              :          END IF
    3705              :       END IF
    3706              : 
    3707              :       IF (do_ot_sd) THEN
    3708         1085 :          qs_ot_env(1)%OT_METHOD_FULL = "OT SD"
    3709         1085 :          IF (do_ks) THEN
    3710         2288 :             DO ispin = 1, nspin
    3711         1203 :                CALL dbcsr_set(qs_ot_env(ispin)%matrix_x, 0.0_dp)
    3712              :                CALL dbcsr_add(qs_ot_env(ispin)%matrix_x, &
    3713              :                               qs_ot_env(ispin)%matrix_h_e(j)%matrix, &
    3714         1203 :                               1.0_dp, 1.0_dp)
    3715              :                CALL dbcsr_add(qs_ot_env(ispin)%matrix_x, &
    3716              :                               qs_ot_env(ispin)%matrix_h_x(j)%matrix, &
    3717         1203 :                               1.0_dp, 1.0_dp)
    3718         1203 :                IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    3719           35 :                   CALL dbcsr_set(qs_ot_env(ispin)%matrix_x_im, 0.0_dp)
    3720              :                   CALL dbcsr_add(qs_ot_env(ispin)%matrix_x_im, &
    3721              :                                  qs_ot_env(ispin)%matrix_h_e_im(j)%matrix, &
    3722           35 :                                  1.0_dp, 1.0_dp)
    3723              :                   CALL dbcsr_add(qs_ot_env(ispin)%matrix_x_im, &
    3724              :                                  qs_ot_env(ispin)%matrix_h_x_im(j)%matrix, &
    3725           35 :                                  1.0_dp, 1.0_dp)
    3726              :                END IF
    3727         2288 :                IF (qs_ot_env(ispin)%settings%do_rotation) THEN
    3728           56 :                   CALL dbcsr_set(qs_ot_env(ispin)%rot_mat_x, 0.0_dp)
    3729           56 :                   IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    3730           28 :                      CALL dbcsr_set(qs_ot_env(ispin)%rot_mat_x_im, 0.0_dp)
    3731              :                   END IF
    3732              :                   CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_x, &
    3733              :                                  qs_ot_env(ispin)%rot_mat_h_e(j)%matrix, &
    3734           56 :                                  1.0_dp, 1.0_dp)
    3735           56 :                   IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    3736              :                      CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_x_im, &
    3737              :                                     qs_ot_env(ispin)%rot_mat_h_e_im(j)%matrix, &
    3738           28 :                                     1.0_dp, 1.0_dp)
    3739              :                   END IF
    3740              :                   CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_x, &
    3741              :                                  qs_ot_env(ispin)%rot_mat_h_x(j)%matrix, &
    3742           56 :                                  1.0_dp, 1.0_dp)
    3743           56 :                   IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    3744              :                      CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_x_im, &
    3745              :                                     qs_ot_env(ispin)%rot_mat_h_x_im(j)%matrix, &
    3746           28 :                                     1.0_dp, 1.0_dp)
    3747              :                   END IF
    3748              :                END IF
    3749              :             END DO
    3750              :          END IF
    3751         1085 :          IF (do_ener) THEN
    3752           54 :             DO ispin = 1, nspin
    3753          284 :                qs_ot_env(ispin)%ener_x(:) = 0._dp
    3754          284 :                qs_ot_env(ispin)%ener_x(:) = qs_ot_env(ispin)%ener_x(:) + qs_ot_env(ispin)%ener_h_e(j, :)
    3755          310 :                qs_ot_env(ispin)%ener_x(:) = qs_ot_env(ispin)%ener_x(:) + qs_ot_env(ispin)%ener_h_x(j, :)
    3756              :             END DO
    3757              :          END IF
    3758              :       END IF
    3759              : 
    3760        50452 :       CALL timestop(handle)
    3761              : 
    3762        50452 :    END SUBROUTINE ot_diis_step
    3763              : 
    3764              : ! **************************************************************************************************
    3765              : !> \brief Energy minimizer by Broyden's method
    3766              : !> \param qs_ot_env variable to control minimizer behaviour
    3767              : !> \param para_env_inter_kp communicator between distributed k-point groups
    3768              : !> \author Kurt Baarman (09.2010)
    3769              : ! **************************************************************************************************
    3770          206 :    SUBROUTINE ot_broyden_step(qs_ot_env, para_env_inter_kp)
    3771              :       TYPE(qs_ot_type), DIMENSION(:), POINTER            :: qs_ot_env
    3772              :       TYPE(mp_para_env_type), OPTIONAL, POINTER          :: para_env_inter_kp
    3773              : 
    3774              :       INTEGER, PARAMETER                                 :: broyden_gradient = 4, &
    3775              :                                                             broyden_position = 1, &
    3776              :                                                             broyden_random = 3, &
    3777              :                                                             broyden_residual = 2
    3778              :       INTEGER                                            :: diis_bound, diis_m, i, ispin, itmp, j, &
    3779              :                                                             k, n, nener, nspin
    3780              :       INTEGER(KIND=int_8)                                :: nrotation, nvariables
    3781          206 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: circ_index
    3782              :       LOGICAL                                            :: adaptive_sigma, do_ener, do_ks, &
    3783              :                                                             do_rotation, enable_flip, forget_history
    3784              :       REAL(KIND=dp)                                      :: beta, eta, gamma, omega, sigma, &
    3785              :                                                             sigma_dec, sigma_min, tmp, tmp2, &
    3786              :                                                             nvariables_global
    3787          206 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: f, x
    3788          206 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: G, S
    3789          206 :       eta = qs_ot_env(1)%settings%broyden_eta
    3790          206 :       omega = qs_ot_env(1)%settings%broyden_omega
    3791          206 :       sigma_dec = qs_ot_env(1)%settings%broyden_sigma_decrease
    3792          206 :       sigma_min = qs_ot_env(1)%settings%broyden_sigma_min
    3793          206 :       forget_history = qs_ot_env(1)%settings%broyden_forget_history
    3794          206 :       adaptive_sigma = qs_ot_env(1)%settings%broyden_adaptive_sigma
    3795          206 :       enable_flip = qs_ot_env(1)%settings%broyden_enable_flip
    3796          206 :       do_ks = qs_ot_env(1)%settings%ks
    3797          206 :       do_ener = qs_ot_env(1)%settings%do_ener
    3798          206 :       do_rotation = qs_ot_env(1)%settings%do_rotation
    3799              : 
    3800          206 :       beta = qs_ot_env(1)%settings%broyden_beta
    3801          206 :       gamma = qs_ot_env(1)%settings%broyden_gamma
    3802          206 :       IF (adaptive_sigma) THEN
    3803          206 :          IF (qs_ot_env(1)%broyden_adaptive_sigma < 0.0_dp) THEN
    3804            8 :             sigma = qs_ot_env(1)%settings%broyden_sigma
    3805              :          ELSE
    3806              :             sigma = qs_ot_env(1)%broyden_adaptive_sigma
    3807              :          END IF
    3808              :       ELSE
    3809            0 :          sigma = qs_ot_env(1)%settings%broyden_sigma
    3810              :       END IF
    3811              : 
    3812          206 :       IF (.NOT. do_ks) CPABORT("BROYDEN currently requires OT orbital variables")
    3813              : 
    3814          206 :       nspin = SIZE(qs_ot_env)
    3815              : 
    3816          206 :       diis_m = qs_ot_env(1)%settings%diis_m
    3817              : 
    3818          206 :       IF (qs_ot_env(1)%diis_iter < diis_m) THEN
    3819           98 :          diis_bound = qs_ot_env(1)%diis_iter + 1
    3820              :       ELSE
    3821          108 :          diis_bound = diis_m
    3822              :       END IF
    3823              : 
    3824              :       ! We want x:s, f:s and one random vector
    3825          206 :       k = 2*diis_bound + 1
    3826          824 :       ALLOCATE (S(k, k))
    3827          618 :       ALLOCATE (G(k, k))
    3828          618 :       ALLOCATE (f(k))
    3829          412 :       ALLOCATE (x(k))
    3830          618 :       ALLOCATE (circ_index(diis_bound))
    3831          206 :       G = 0.0_dp
    3832         2668 :       DO i = 1, k
    3833         2668 :          G(i, i) = sigma
    3834              :       END DO
    3835          206 :       S = 0.0_dp
    3836              : 
    3837          206 :       j = MOD(qs_ot_env(1)%diis_iter, diis_m) + 1 ! index in the circular array
    3838              : 
    3839          206 :       CALL broyden_copy_current_to_history(j)
    3840              :       CALL ot_build_history_residual(qs_ot_env, j, -1.0_dp, para_env_inter_kp, &
    3841          206 :                                      qs_ot_env(1)%gnorm)
    3842          206 :       IF (qs_ot_env(1)%settings%occupation_preconditioner) THEN
    3843           28 :          CALL broyden_bound_occupation_response(j, qs_ot_env(1)%gnorm)
    3844              :       END IF
    3845              : 
    3846          206 :       k = 0
    3847              :       n = 0
    3848          206 :       nener = 0
    3849          206 :       nrotation = 0_int_8
    3850          206 :       CALL dbcsr_get_info(qs_ot_env(1)%matrix_x, nfullrows_total=n)
    3851          440 :       DO ispin = 1, nspin
    3852          234 :          CALL dbcsr_get_info(qs_ot_env(ispin)%matrix_x, nfullcols_total=itmp)
    3853          234 :          k = k + itmp
    3854          234 :          IF (qs_ot_env(ispin)%has_complex_kpoint_state) k = k + itmp
    3855          234 :          IF (do_rotation) THEN
    3856           56 :             nrotation = nrotation + INT(itmp, KIND=int_8)*INT(itmp - 1, KIND=int_8)/2_int_8
    3857           56 :             IF (qs_ot_env(ispin)%has_complex_kpoint_state) THEN
    3858           56 :                nrotation = nrotation + INT(itmp, KIND=int_8)*INT(itmp + 1, KIND=int_8)/2_int_8
    3859              :             END IF
    3860              :          END IF
    3861          674 :          IF (do_ener) nener = nener + SIZE(qs_ot_env(ispin)%ener_x)
    3862              :       END DO
    3863              :       nvariables = INT(n, KIND=int_8)*INT(k, KIND=int_8) + nrotation + &
    3864          206 :                    INT(nener, KIND=int_8)
    3865          206 :       nvariables_global = REAL(nvariables, KIND=dp)
    3866          206 :       CALL ot_mini_sum_kpoint_scalar(para_env_inter_kp, nvariables_global)
    3867              : 
    3868              :       ! Handling the case of no free variables to optimize
    3869          206 :       IF (nvariables_global > 0.0_dp) THEN
    3870          206 :          qs_ot_env(1)%delta = SQRT(ABS(qs_ot_env(1)%gnorm)/nvariables_global)
    3871          206 :          qs_ot_env(1)%gradient = -qs_ot_env(1)%gnorm
    3872              :       ELSE
    3873            0 :          qs_ot_env(1)%delta = 0.0_dp
    3874            0 :          qs_ot_env(1)%gradient = 0.0_dp
    3875              :       END IF
    3876              : 
    3877          206 :       IF (diis_bound == diis_m) THEN
    3878          960 :          DO i = 1, diis_bound
    3879          960 :             circ_index(i) = MOD(j + i - 1, diis_m) + 1
    3880              :          END DO
    3881              :       ELSE
    3882          374 :          DO i = 1, diis_bound
    3883          374 :             circ_index(i) = i
    3884              :          END DO
    3885              :       END IF
    3886              : 
    3887          206 :       S = 0.0_dp
    3888          206 :       CALL broyden_randomize_current()
    3889         1334 :       DO i = 1, diis_bound
    3890              :          CALL broyden_product_dot(broyden_position, circ_index(i), &
    3891         1128 :                                   broyden_position, circ_index(i), S(i, i))
    3892              :          CALL broyden_product_dot(broyden_residual, circ_index(i), &
    3893              :                                   broyden_residual, circ_index(i), &
    3894         1128 :                                   S(i + diis_bound, i + diis_bound))
    3895              :          ! Preserve the established Broyden model, whose auxiliary vector is orthogonal to history.
    3896         1128 :          S(i, 2*diis_bound + 1) = 0.0_dp
    3897         1128 :          S(2*diis_bound + 1, i) = 0.0_dp
    3898         1128 :          S(i + diis_bound, 2*diis_bound + 1) = 0.0_dp
    3899         1128 :          S(2*diis_bound + 1, i + diis_bound) = 0.0_dp
    3900         4110 :          DO k = i + 1, diis_bound
    3901              :             CALL broyden_product_dot(broyden_position, circ_index(i), &
    3902         2982 :                                      broyden_position, circ_index(k), S(i, k))
    3903         2982 :             S(k, i) = S(i, k)
    3904              :             CALL broyden_product_dot(broyden_residual, circ_index(i), &
    3905              :                                      broyden_residual, circ_index(k), &
    3906         2982 :                                      S(diis_bound + i, diis_bound + k))
    3907         4110 :             S(diis_bound + k, diis_bound + i) = S(diis_bound + i, diis_bound + k)
    3908              :          END DO
    3909         8426 :          DO k = 1, diis_bound
    3910              :             CALL broyden_product_dot(broyden_position, circ_index(i), &
    3911              :                                      broyden_residual, circ_index(k), &
    3912         7092 :                                      S(i, k + diis_bound))
    3913         8220 :             S(k + diis_bound, i) = S(i, k + diis_bound)
    3914              :          END DO
    3915              :       END DO
    3916              :       CALL broyden_product_dot(broyden_random, 0, broyden_random, 0, &
    3917          206 :                                S(2*diis_bound + 1, 2*diis_bound + 1))
    3918              : 
    3919              :       ! normalize
    3920          206 :       k = 2*diis_bound + 1
    3921          206 :       tmp = SQRT(S(k, k))
    3922         2668 :       S(k, :) = S(k, :)/tmp
    3923         2668 :       S(:, k) = S(:, k)/tmp
    3924              : 
    3925          206 :       IF (diis_bound > 1) THEN
    3926          190 :          tmp2 = 0.0_dp
    3927          190 :          i = diis_bound
    3928              :          CALL broyden_product_dot(broyden_position, circ_index(i), &
    3929          190 :                                   broyden_residual, circ_index(i), tmp)
    3930          190 :          tmp2 = tmp2 + tmp
    3931              :          CALL broyden_product_dot(broyden_position, circ_index(i - 1), &
    3932          190 :                                   broyden_residual, circ_index(i), tmp)
    3933          190 :          tmp2 = tmp2 - tmp
    3934              :          CALL broyden_product_dot(broyden_position, circ_index(i), &
    3935          190 :                                   broyden_residual, circ_index(i - 1), tmp)
    3936          190 :          tmp2 = tmp2 - tmp
    3937              :          CALL broyden_product_dot(broyden_position, circ_index(i - 1), &
    3938          190 :                                   broyden_residual, circ_index(i - 1), tmp)
    3939          190 :          tmp2 = tmp2 + tmp
    3940          190 :          qs_ot_env(1)%c_broy(i - 1) = tmp2
    3941              :       END IF
    3942              : 
    3943          206 :       qs_ot_env(1)%energy_h(j) = qs_ot_env(1)%etotal
    3944              : 
    3945              :       ! If we went uphill, do backtracking line search
    3946         1334 :       i = MINLOC(qs_ot_env(1)%energy_h(1:diis_bound), dim=1)
    3947          206 :       IF (i /= j) THEN
    3948           26 :          sigma = sigma_dec*sigma
    3949           26 :          qs_ot_env(1)%OT_METHOD_FULL = "OT BTRK"
    3950           26 :          CALL broyden_set_current_zero()
    3951           26 :          CALL broyden_add_history(broyden_position, i, 1.0_dp, 1.0_dp - gamma)
    3952           26 :          CALL broyden_add_history(broyden_position, circ_index(diis_bound), 1.0_dp, gamma)
    3953              :       ELSE
    3954              :          ! Construct G
    3955          946 :          DO i = 2, diis_bound
    3956          766 :             f = 0.0_dp
    3957          766 :             x = 0.0_dp
    3958              :             ! f is df_i
    3959          766 :             x(i) = 1.0_dp
    3960          766 :             x(i - 1) = -1.0_dp
    3961              :             ! x is dx_i
    3962          766 :             f(diis_bound + i) = 1.0_dp
    3963          766 :             f(diis_bound + i - 1) = -1.0_dp
    3964          766 :             tmp = 1.0_dp
    3965              :             ! We want a pos def Hessian
    3966          766 :             IF (enable_flip) THEN
    3967          766 :                IF (qs_ot_env(1)%c_broy(i - 1) > 0) THEN
    3968              :                   !qs_ot_env(1)%OT_METHOD_FULL="OT FLIP"
    3969            2 :                   tmp = -1.0_dp
    3970              :                END IF
    3971              :             END IF
    3972              : 
    3973              :             ! get dx-Gdf
    3974       470288 :             x(:) = tmp*x - MATMUL(G, f)
    3975              :             ! dfSdf
    3976              :             ! we calculate matmul(S, f) twice. They're small...
    3977       470288 :             tmp = DOT_PRODUCT(f, MATMUL(S, f))
    3978              :             ! NOTE THAT S IS SYMMETRIC !!!
    3979       470288 :             f(:) = MATMUL(S, f)/tmp
    3980              :             ! the spread is an outer vector product
    3981       160446 :             G(:, :) = G + SPREAD(x, dim=2, ncopies=SIZE(f))*SPREAD(f, dim=1, ncopies=SIZE(x))
    3982              :          END DO
    3983          180 :          f = 0.0_dp
    3984          180 :          f(2*diis_bound) = 1.0_dp
    3985       113268 :          x(:) = -beta*MATMUL(G, f)
    3986              : 
    3987              :          ! OK, add the vectors now, this sums up to the proposed step
    3988          180 :          CALL broyden_set_current_zero()
    3989         1126 :          DO i = 1, diis_bound
    3990              :             CALL broyden_add_history(broyden_residual, circ_index(i), 1.0_dp, &
    3991         1126 :                                      -x(i + diis_bound))
    3992              :          END DO
    3993         1126 :          DO i = 1, diis_bound
    3994         1126 :             CALL broyden_add_history(broyden_position, circ_index(i), 1.0_dp, x(i))
    3995              :          END DO
    3996              : 
    3997          180 :          IF (adaptive_sigma) THEN
    3998          180 :             tmp = new_sigma(G, S, diis_bound)
    3999              :             !tmp = tmp * qs_ot_env ( 1 ) % settings % broyden_sigma
    4000          180 :             tmp = tmp*eta
    4001          180 :             sigma = MIN(omega*sigma, tmp)
    4002              :          END IF
    4003              : 
    4004              :          ! compute the inner product of direction of the step and gradient
    4005          180 :          CALL broyden_product_dot(broyden_gradient, 0, broyden_random, 0, tmp)
    4006              : 
    4007              :          ! If the direction is not a descent direction, reverse it before adding the current point.
    4008          180 :          IF (tmp >= 0.0_dp) THEN
    4009            8 :             qs_ot_env(1)%OT_METHOD_FULL = "OT TURN"
    4010              :             ! A non-descent product step invalidates the secants that couple orbitals,
    4011              :             ! rotations, and auxiliary energies.  Retain the legacy opt-in behavior
    4012              :             ! for orbital-only OT, but always restart an inconsistent Mermin history.
    4013            8 :             IF (broyden_history_restart_required(.TRUE., forget_history, do_ener)) THEN
    4014            0 :                qs_ot_env(1)%diis_iter = 0
    4015              :             END IF
    4016            8 :             sigma = sigma*sigma_dec
    4017            8 :             CALL broyden_add_history(broyden_position, circ_index(diis_bound), -1.0_dp, 1.0_dp)
    4018              :          ELSE
    4019          172 :             CALL broyden_add_history(broyden_position, circ_index(diis_bound), 1.0_dp, 1.0_dp)
    4020              :          END IF
    4021              :       END IF
    4022              : 
    4023              :       ! get rid of S, G, f, x, circ_index for next round
    4024          206 :       DEALLOCATE (S, G, f, x, circ_index)
    4025              : 
    4026              :       ! update for next round
    4027          206 :       qs_ot_env(1)%diis_iter = qs_ot_env(1)%diis_iter + 1
    4028          412 :       qs_ot_env(1)%broyden_adaptive_sigma = MAX(sigma, sigma_min)
    4029              : 
    4030              :    CONTAINS
    4031              : 
    4032              : ! **************************************************************************************************
    4033              : !> \brief Bound the occupation-response direction against the conventional OT H0 direction.
    4034              : !> \param history_index response history slot
    4035              : !> \param gnorm physical gradient product with the resulting positive direction
    4036              : ! **************************************************************************************************
    4037           28 :       SUBROUTINE broyden_bound_occupation_response(history_index, gnorm)
    4038              :       INTEGER, INTENT(IN)                                :: history_index
    4039              :       REAL(KIND=dp), INTENT(INOUT)                       :: gnorm
    4040              : 
    4041              :       INTEGER                                            :: ichannel
    4042              :       LOGICAL                                            :: valid_response
    4043              :       REAL(KIND=dp) :: g_dot_h0_g, h0_g_norm_sq, p_dot_h0, response_delta_norm_sq, &
    4044              :          response_norm_sq, response_scale, response_weight
    4045              : 
    4046           28 :          CALL broyden_build_h0_current()
    4047           28 :          CALL broyden_product_dot(broyden_gradient, 0, broyden_random, 0, g_dot_h0_g)
    4048           28 :          CALL broyden_product_dot(broyden_random, 0, broyden_random, 0, h0_g_norm_sq)
    4049              :          CALL broyden_product_dot(broyden_residual, history_index, &
    4050           28 :                                   broyden_residual, history_index, response_norm_sq)
    4051              :          CALL broyden_product_dot(broyden_residual, history_index, &
    4052           28 :                                   broyden_random, 0, p_dot_h0)
    4053           28 :          p_dot_h0 = -p_dot_h0
    4054           28 :          response_delta_norm_sq = response_norm_sq + h0_g_norm_sq - 2.0_dp*p_dot_h0
    4055              :          valid_response = ieee_is_finite(gnorm) .AND. ieee_is_finite(response_norm_sq) .AND. &
    4056              :                           ieee_is_finite(g_dot_h0_g) .AND. ieee_is_finite(h0_g_norm_sq) .AND. &
    4057              :                           ieee_is_finite(response_delta_norm_sq) .AND. gnorm > 0.0_dp .AND. &
    4058              :                           g_dot_h0_g > 0.0_dp .AND. h0_g_norm_sq > TINY(1.0_dp) .AND. &
    4059           28 :                           response_delta_norm_sq >= 0.0_dp
    4060           56 :          response_scale = 1.0_dp
    4061           28 :          response_weight = 0.0_dp
    4062              :          IF (valid_response) THEN
    4063              :             ! Keep the response correction inside a product-norm trust ball around H0*g.
    4064              :             response_weight = MIN(1.0_dp, SQRT(h0_g_norm_sq/ &
    4065           28 :                                                MAX(response_delta_norm_sq, TINY(1.0_dp))))
    4066              :          END IF
    4067              :          ! Broyden secants require a consistent residual map. Use the state-dependent occupation
    4068              :          ! response only to seed the first direction, then let the history learn from frozen H0*g.
    4069           28 :          IF (qs_ot_env(1)%diis_iter > 0) response_weight = 0.0_dp
    4070           28 :          IF (.NOT. valid_response) THEN
    4071            0 :             response_scale = 0.0_dp
    4072            0 :             response_weight = 0.0_dp
    4073              :          END IF
    4074              : 
    4075           84 :          DO ichannel = 1, nspin
    4076              :             CALL dbcsr_scale(qs_ot_env(ichannel)%matrix_h_e(history_index)%matrix, &
    4077           56 :                              response_weight*response_scale)
    4078              :             CALL dbcsr_add(qs_ot_env(ichannel)%matrix_h_e(history_index)%matrix, &
    4079           56 :                            qs_ot_env(ichannel)%matrix_x, 1.0_dp, -(1.0_dp - response_weight))
    4080           56 :             IF (qs_ot_env(ichannel)%has_complex_kpoint_state) THEN
    4081              :                CALL dbcsr_scale(qs_ot_env(ichannel)%matrix_h_e_im(history_index)%matrix, &
    4082           56 :                                 response_weight*response_scale)
    4083              :                CALL dbcsr_add(qs_ot_env(ichannel)%matrix_h_e_im(history_index)%matrix, &
    4084              :                               qs_ot_env(ichannel)%matrix_x_im, 1.0_dp, &
    4085           56 :                               -(1.0_dp - response_weight))
    4086              :             END IF
    4087           56 :             IF (do_rotation) THEN
    4088              :                CALL dbcsr_scale(qs_ot_env(ichannel)%rot_mat_h_e(history_index)%matrix, &
    4089           56 :                                 response_weight*response_scale)
    4090              :                CALL dbcsr_add(qs_ot_env(ichannel)%rot_mat_h_e(history_index)%matrix, &
    4091              :                               qs_ot_env(ichannel)%rot_mat_x, 1.0_dp, &
    4092           56 :                               -(1.0_dp - response_weight))
    4093           56 :                IF (qs_ot_env(ichannel)%has_complex_kpoint_state) THEN
    4094              :                   CALL dbcsr_scale(qs_ot_env(ichannel)%rot_mat_h_e_im(history_index)%matrix, &
    4095           56 :                                    response_weight*response_scale)
    4096              :                   CALL dbcsr_add(qs_ot_env(ichannel)%rot_mat_h_e_im(history_index)%matrix, &
    4097              :                                  qs_ot_env(ichannel)%rot_mat_x_im, 1.0_dp, &
    4098           56 :                                  -(1.0_dp - response_weight))
    4099              :                END IF
    4100              :             END IF
    4101           84 :             IF (do_ener) THEN
    4102              :                qs_ot_env(ichannel)%ener_h_e(history_index, :) = &
    4103              :                   response_weight*response_scale*qs_ot_env(ichannel)%ener_h_e(history_index, :) - &
    4104          224 :                   (1.0_dp - response_weight)*qs_ot_env(ichannel)%ener_x
    4105              :             END IF
    4106              :          END DO
    4107           28 :          IF (valid_response) THEN
    4108              :             gnorm = response_weight*response_scale*gnorm + &
    4109           28 :                     (1.0_dp - response_weight)*g_dot_h0_g
    4110              :          ELSE
    4111            0 :             gnorm = g_dot_h0_g
    4112              :          END IF
    4113           28 :       END SUBROUTINE broyden_bound_occupation_response
    4114              : 
    4115              : ! **************************************************************************************************
    4116              : !> \brief Store the conventional positive OT H0 direction in the current product coordinate.
    4117              : ! **************************************************************************************************
    4118           28 :       SUBROUTINE broyden_build_h0_current()
    4119              :       INTEGER                                            :: ichannel
    4120              :       REAL(KIND=dp)                                      :: kpoint_scale
    4121              : 
    4122           84 :          DO ichannel = 1, nspin
    4123           56 :             IF (ASSOCIATED(qs_ot_env(1)%preconditioner)) THEN
    4124           56 :                IF (qs_ot_env(ichannel)%has_complex_kpoint_state) THEN
    4125              :                   CALL apply_preconditioner(qs_ot_env(ichannel)%preconditioner, &
    4126              :                                             qs_ot_env(ichannel)%matrix_gx, &
    4127              :                                             qs_ot_env(ichannel)%matrix_gx_im, &
    4128              :                                             qs_ot_env(ichannel)%matrix_x, &
    4129           56 :                                             qs_ot_env(ichannel)%matrix_x_im)
    4130           56 :                   CPASSERT(qs_ot_env(ichannel)%kpoint_weight > 0.0_dp)
    4131              :                   kpoint_scale = qs_ot_kpoint_preconditioner_scale( &
    4132           56 :                                  qs_ot_env(ichannel)%kpoint_weight)
    4133           56 :                   CALL dbcsr_scale(qs_ot_env(ichannel)%matrix_x, kpoint_scale)
    4134           56 :                   CALL dbcsr_scale(qs_ot_env(ichannel)%matrix_x_im, kpoint_scale)
    4135              :                ELSE
    4136              :                   CALL apply_preconditioner(qs_ot_env(ichannel)%preconditioner, &
    4137              :                                             qs_ot_env(ichannel)%matrix_gx, &
    4138            0 :                                             qs_ot_env(ichannel)%matrix_x)
    4139              :                END IF
    4140              :             ELSE
    4141            0 :                CALL dbcsr_copy(qs_ot_env(ichannel)%matrix_x, qs_ot_env(ichannel)%matrix_gx)
    4142            0 :                IF (qs_ot_env(ichannel)%has_complex_kpoint_state) THEN
    4143              :                   CALL dbcsr_copy(qs_ot_env(ichannel)%matrix_x_im, &
    4144            0 :                                   qs_ot_env(ichannel)%matrix_gx_im)
    4145              :                END IF
    4146              :             END IF
    4147           56 :             IF (do_rotation) THEN
    4148           56 :                CALL dbcsr_copy(qs_ot_env(ichannel)%rot_mat_x, qs_ot_env(ichannel)%rot_mat_gx)
    4149           56 :                IF (qs_ot_env(ichannel)%has_complex_kpoint_state) THEN
    4150              :                   CALL dbcsr_copy(qs_ot_env(ichannel)%rot_mat_x_im, &
    4151           56 :                                   qs_ot_env(ichannel)%rot_mat_gx_im)
    4152              :                END IF
    4153              :             END IF
    4154          252 :             IF (do_ener) qs_ot_env(ichannel)%ener_x = qs_ot_env(ichannel)%ener_gx
    4155              :          END DO
    4156           28 :       END SUBROUTINE broyden_build_h0_current
    4157              : 
    4158              : ! **************************************************************************************************
    4159              : !> \brief Copy all current product coordinates into a Broyden history slot.
    4160              : !> \param history_index destination history slot
    4161              : ! **************************************************************************************************
    4162          206 :       SUBROUTINE broyden_copy_current_to_history(history_index)
    4163              :       INTEGER, INTENT(IN)                                :: history_index
    4164              : 
    4165              :       INTEGER                                            :: ichannel
    4166              : 
    4167          440 :          DO ichannel = 1, nspin
    4168              :             CALL dbcsr_copy(qs_ot_env(ichannel)%matrix_h_x(history_index)%matrix, &
    4169          234 :                             qs_ot_env(ichannel)%matrix_x)
    4170          234 :             IF (qs_ot_env(ichannel)%has_complex_kpoint_state) THEN
    4171              :                CALL dbcsr_copy(qs_ot_env(ichannel)%matrix_h_x_im(history_index)%matrix, &
    4172           56 :                                qs_ot_env(ichannel)%matrix_x_im)
    4173              :             END IF
    4174          234 :             IF (do_rotation) THEN
    4175              :                CALL dbcsr_copy(qs_ot_env(ichannel)%rot_mat_h_x(history_index)%matrix, &
    4176           56 :                                qs_ot_env(ichannel)%rot_mat_x)
    4177           56 :                IF (qs_ot_env(ichannel)%has_complex_kpoint_state) THEN
    4178              :                   CALL dbcsr_copy(qs_ot_env(ichannel)%rot_mat_h_x_im(history_index)%matrix, &
    4179           56 :                                   qs_ot_env(ichannel)%rot_mat_x_im)
    4180              :                END IF
    4181              :             END IF
    4182          440 :             IF (do_ener) THEN
    4183          224 :                qs_ot_env(ichannel)%ener_h_x(history_index, :) = qs_ot_env(ichannel)%ener_x
    4184              :             END IF
    4185              :          END DO
    4186          206 :       END SUBROUTINE broyden_copy_current_to_history
    4187              : 
    4188              : ! **************************************************************************************************
    4189              : !> \brief Fill the current product coordinate with a deterministic auxiliary vector.
    4190              : ! **************************************************************************************************
    4191          206 :       SUBROUTINE broyden_randomize_current()
    4192              :       INTEGER                                            :: ichannel, icoef
    4193              : 
    4194          440 :          DO ichannel = 1, nspin
    4195          234 :             CALL dbcsr_init_random(qs_ot_env(ichannel)%matrix_x)
    4196          234 :             IF (qs_ot_env(ichannel)%has_complex_kpoint_state) THEN
    4197           56 :                CALL dbcsr_init_random(qs_ot_env(ichannel)%matrix_x_im)
    4198              :             END IF
    4199          234 :             IF (do_rotation) THEN
    4200           56 :                CALL dbcsr_init_random(qs_ot_env(ichannel)%rot_mat_x)
    4201           56 :                IF (qs_ot_env(ichannel)%has_complex_kpoint_state) THEN
    4202           56 :                   CALL dbcsr_init_random(qs_ot_env(ichannel)%rot_mat_x_im)
    4203              :                END IF
    4204              :             END IF
    4205          440 :             IF (do_ener) THEN
    4206          224 :                DO icoef = 1, SIZE(qs_ot_env(ichannel)%ener_x)
    4207              :                   qs_ot_env(ichannel)%ener_x(icoef) = SIN(REAL(icoef + &
    4208              :                                                                37*qs_ot_env(ichannel)%spin_index + &
    4209          224 :                                                                101*qs_ot_env(ichannel)%kpoint_index, KIND=dp))
    4210              :                END DO
    4211              :             END IF
    4212              :          END DO
    4213          206 :       END SUBROUTINE broyden_randomize_current
    4214              : 
    4215              : ! **************************************************************************************************
    4216              : !> \brief Set all current product coordinates to zero.
    4217              : ! **************************************************************************************************
    4218          206 :       SUBROUTINE broyden_set_current_zero()
    4219              :       INTEGER                                            :: ichannel
    4220              : 
    4221          440 :          DO ichannel = 1, nspin
    4222          234 :             CALL dbcsr_set(qs_ot_env(ichannel)%matrix_x, 0.0_dp)
    4223          234 :             IF (qs_ot_env(ichannel)%has_complex_kpoint_state) THEN
    4224           56 :                CALL dbcsr_set(qs_ot_env(ichannel)%matrix_x_im, 0.0_dp)
    4225              :             END IF
    4226          234 :             IF (do_rotation) THEN
    4227           56 :                CALL dbcsr_set(qs_ot_env(ichannel)%rot_mat_x, 0.0_dp)
    4228           56 :                IF (qs_ot_env(ichannel)%has_complex_kpoint_state) THEN
    4229           56 :                   CALL dbcsr_set(qs_ot_env(ichannel)%rot_mat_x_im, 0.0_dp)
    4230              :                END IF
    4231              :             END IF
    4232          608 :             IF (do_ener) qs_ot_env(ichannel)%ener_x = 0.0_dp
    4233              :          END DO
    4234          206 :       END SUBROUTINE broyden_set_current_zero
    4235              : 
    4236              : ! **************************************************************************************************
    4237              : !> \brief Add one stored product vector to the current coordinate.
    4238              : !> \param vector_kind position or residual history
    4239              : !> \param history_index source history slot
    4240              : !> \param alpha_current scale of the current coordinate
    4241              : !> \param beta_history scale of the stored coordinate
    4242              : ! **************************************************************************************************
    4243         2124 :       SUBROUTINE broyden_add_history(vector_kind, history_index, alpha_current, beta_history)
    4244              :       INTEGER, INTENT(IN)                                :: vector_kind, history_index
    4245              :       REAL(KIND=dp), INTENT(IN)                          :: alpha_current, beta_history
    4246              : 
    4247              :       INTEGER                                            :: ichannel
    4248              :       TYPE(dbcsr_type), POINTER                          :: source
    4249              : 
    4250         4584 :          DO ichannel = 1, nspin
    4251         2460 :             CALL broyden_matrix_pointer(vector_kind, history_index, ichannel, .FALSE., .FALSE., source)
    4252         2460 :             CALL dbcsr_add(qs_ot_env(ichannel)%matrix_x, source, alpha_current, beta_history)
    4253         2460 :             IF (qs_ot_env(ichannel)%has_complex_kpoint_state) THEN
    4254          672 :                CALL broyden_matrix_pointer(vector_kind, history_index, ichannel, .TRUE., .FALSE., source)
    4255          672 :                CALL dbcsr_add(qs_ot_env(ichannel)%matrix_x_im, source, alpha_current, beta_history)
    4256              :             END IF
    4257         2460 :             IF (do_rotation) THEN
    4258          672 :                CALL broyden_matrix_pointer(vector_kind, history_index, ichannel, .FALSE., .TRUE., source)
    4259          672 :                CALL dbcsr_add(qs_ot_env(ichannel)%rot_mat_x, source, alpha_current, beta_history)
    4260          672 :                IF (qs_ot_env(ichannel)%has_complex_kpoint_state) THEN
    4261          672 :                   CALL broyden_matrix_pointer(vector_kind, history_index, ichannel, .TRUE., .TRUE., source)
    4262          672 :                   CALL dbcsr_add(qs_ot_env(ichannel)%rot_mat_x_im, source, alpha_current, beta_history)
    4263              :                END IF
    4264              :             END IF
    4265         4584 :             IF (do_ener) THEN
    4266         1036 :                SELECT CASE (vector_kind)
    4267              :                CASE (broyden_position)
    4268              :                   qs_ot_env(ichannel)%ener_x = alpha_current*qs_ot_env(ichannel)%ener_x + &
    4269         1456 :                                                beta_history*qs_ot_env(ichannel)%ener_h_x(history_index, :)
    4270              :                CASE (broyden_residual)
    4271              :                   qs_ot_env(ichannel)%ener_x = alpha_current*qs_ot_env(ichannel)%ener_x + &
    4272         1232 :                                                beta_history*qs_ot_env(ichannel)%ener_h_e(history_index, :)
    4273              :                CASE DEFAULT
    4274          672 :                   CPABORT("Invalid Broyden history vector kind")
    4275              :                END SELECT
    4276              :             END IF
    4277              :          END DO
    4278         2124 :       END SUBROUTINE broyden_add_history
    4279              : 
    4280              : ! **************************************************************************************************
    4281              : !> \brief Product-space scalar product including complex, rotation, and energy coordinates.
    4282              : !> \param kind_a first vector kind
    4283              : !> \param index_a first history index, ignored for current/gradient vectors
    4284              : !> \param kind_b second vector kind
    4285              : !> \param index_b second history index, ignored for current/gradient vectors
    4286              : !> \param value globally reduced scalar product
    4287              : ! **************************************************************************************************
    4288        16570 :       SUBROUTINE broyden_product_dot(kind_a, index_a, kind_b, index_b, value)
    4289              :       INTEGER, INTENT(IN)                                :: kind_a, index_a, kind_b, index_b
    4290              :       REAL(KIND=dp), INTENT(OUT)                         :: value
    4291              : 
    4292              :       INTEGER                                            :: ichannel
    4293              :       REAL(KIND=dp)                                      :: dot_value
    4294              :       REAL(KIND=dp), DIMENSION(:), POINTER               :: energy_a, energy_b
    4295              :       TYPE(dbcsr_type), POINTER                          :: matrix_a, matrix_b
    4296              : 
    4297        16570 :          value = 0.0_dp
    4298        35498 :          DO ichannel = 1, nspin
    4299        18928 :             CALL broyden_matrix_pointer(kind_a, index_a, ichannel, .FALSE., .FALSE., matrix_a)
    4300        18928 :             CALL broyden_matrix_pointer(kind_b, index_b, ichannel, .FALSE., .FALSE., matrix_b)
    4301        18928 :             CALL dbcsr_dot(matrix_a, matrix_b, dot_value)
    4302        18928 :             value = value + dot_value
    4303        18928 :             IF (qs_ot_env(ichannel)%has_complex_kpoint_state) THEN
    4304         4716 :                CALL broyden_matrix_pointer(kind_a, index_a, ichannel, .TRUE., .FALSE., matrix_a)
    4305         4716 :                CALL broyden_matrix_pointer(kind_b, index_b, ichannel, .TRUE., .FALSE., matrix_b)
    4306         4716 :                CALL dbcsr_dot(matrix_a, matrix_b, dot_value)
    4307         4716 :                value = value + dot_value
    4308              :             END IF
    4309        18928 :             IF (do_rotation) THEN
    4310         4716 :                CALL broyden_matrix_pointer(kind_a, index_a, ichannel, .FALSE., .TRUE., matrix_a)
    4311         4716 :                CALL broyden_matrix_pointer(kind_b, index_b, ichannel, .FALSE., .TRUE., matrix_b)
    4312         4716 :                CALL dbcsr_dot(matrix_a, matrix_b, dot_value)
    4313         4716 :                value = value + 0.5_dp*dot_value
    4314         4716 :                IF (qs_ot_env(ichannel)%has_complex_kpoint_state) THEN
    4315         4716 :                   CALL broyden_matrix_pointer(kind_a, index_a, ichannel, .TRUE., .TRUE., matrix_a)
    4316         4716 :                   CALL broyden_matrix_pointer(kind_b, index_b, ichannel, .TRUE., .TRUE., matrix_b)
    4317         4716 :                   CALL dbcsr_dot(matrix_a, matrix_b, dot_value)
    4318         4716 :                   value = value + 0.5_dp*dot_value
    4319              :                END IF
    4320              :             END IF
    4321        54426 :             IF (do_ener) THEN
    4322         4716 :                CALL broyden_energy_pointer(kind_a, index_a, ichannel, energy_a)
    4323         4716 :                CALL broyden_energy_pointer(kind_b, index_b, ichannel, energy_b)
    4324        18864 :                value = value + DOT_PRODUCT(energy_a, energy_b)
    4325              :             END IF
    4326              :          END DO
    4327        16570 :          CALL ot_mini_sum_kpoint_scalar(para_env_inter_kp, value)
    4328        16570 :       END SUBROUTINE broyden_product_dot
    4329              : 
    4330              : ! **************************************************************************************************
    4331              : !> \brief Select one orbital or rotation matrix from the product-vector storage.
    4332              : !> \param vector_kind vector kind
    4333              : !> \param history_index history slot
    4334              : !> \param channel local spin/k-point channel
    4335              : !> \param imaginary select imaginary component
    4336              : !> \param rotation select rotation instead of orbital component
    4337              : !> \param matrix selected matrix
    4338              : ! **************************************************************************************************
    4339        70628 :       SUBROUTINE broyden_matrix_pointer(vector_kind, history_index, channel, imaginary, rotation, matrix)
    4340              :       INTEGER, INTENT(IN)                                :: vector_kind, history_index, channel
    4341              :       LOGICAL, INTENT(IN)                                :: imaginary, rotation
    4342              :       TYPE(dbcsr_type), POINTER                          :: matrix
    4343              : 
    4344        70628 :          IF (imaginary) THEN
    4345        20208 :             CPASSERT(qs_ot_env(channel)%has_complex_kpoint_state)
    4346              :          END IF
    4347       104482 :          SELECT CASE (vector_kind)
    4348              :          CASE (broyden_position)
    4349        33854 :             CPASSERT(history_index > 0)
    4350        33854 :             IF (rotation) THEN
    4351         9488 :                IF (imaginary) THEN
    4352         4744 :                   matrix => qs_ot_env(channel)%rot_mat_h_x_im(history_index)%matrix
    4353              :                ELSE
    4354         4744 :                   matrix => qs_ot_env(channel)%rot_mat_h_x(history_index)%matrix
    4355              :                END IF
    4356              :             ELSE
    4357        24366 :                IF (imaginary) THEN
    4358         4744 :                   matrix => qs_ot_env(channel)%matrix_h_x_im(history_index)%matrix
    4359              :                ELSE
    4360        19622 :                   matrix => qs_ot_env(channel)%matrix_h_x(history_index)%matrix
    4361              :                END IF
    4362              :             END IF
    4363              :          CASE (broyden_residual)
    4364        34098 :             CPASSERT(history_index > 0)
    4365        34098 :             IF (rotation) THEN
    4366         9712 :                IF (imaginary) THEN
    4367         4856 :                   matrix => qs_ot_env(channel)%rot_mat_h_e_im(history_index)%matrix
    4368              :                ELSE
    4369         4856 :                   matrix => qs_ot_env(channel)%rot_mat_h_e(history_index)%matrix
    4370              :                END IF
    4371              :             ELSE
    4372        24386 :                IF (imaginary) THEN
    4373         4856 :                   matrix => qs_ot_env(channel)%matrix_h_e_im(history_index)%matrix
    4374              :                ELSE
    4375        19530 :                   matrix => qs_ot_env(channel)%matrix_h_e(history_index)%matrix
    4376              :                END IF
    4377              :             END IF
    4378              :          CASE (broyden_random)
    4379         2076 :             IF (rotation) THEN
    4380          784 :                IF (imaginary) THEN
    4381          392 :                   matrix => qs_ot_env(channel)%rot_mat_x_im
    4382              :                ELSE
    4383          392 :                   matrix => qs_ot_env(channel)%rot_mat_x
    4384              :                END IF
    4385              :             ELSE
    4386         1292 :                IF (imaginary) THEN
    4387          392 :                   matrix => qs_ot_env(channel)%matrix_x_im
    4388              :                ELSE
    4389          900 :                   matrix => qs_ot_env(channel)%matrix_x
    4390              :                END IF
    4391              :             END IF
    4392              :          CASE (broyden_gradient)
    4393          600 :             IF (rotation) THEN
    4394          224 :                IF (imaginary) THEN
    4395          112 :                   matrix => qs_ot_env(channel)%rot_mat_gx_im
    4396              :                ELSE
    4397          112 :                   matrix => qs_ot_env(channel)%rot_mat_gx
    4398              :                END IF
    4399              :             ELSE
    4400          376 :                IF (imaginary) THEN
    4401          112 :                   matrix => qs_ot_env(channel)%matrix_gx_im
    4402              :                ELSE
    4403          264 :                   matrix => qs_ot_env(channel)%matrix_gx
    4404              :                END IF
    4405              :             END IF
    4406              :          CASE DEFAULT
    4407        70628 :             CPABORT("Invalid Broyden product vector kind")
    4408              :          END SELECT
    4409        70628 :       END SUBROUTINE broyden_matrix_pointer
    4410              : 
    4411              : ! **************************************************************************************************
    4412              : !> \brief Select one energy-variable vector from the product-vector storage.
    4413              : !> \param vector_kind vector kind
    4414              : !> \param history_index history slot
    4415              : !> \param channel local spin/k-point channel
    4416              : !> \param energy selected energy vector
    4417              : ! **************************************************************************************************
    4418         9432 :       SUBROUTINE broyden_energy_pointer(vector_kind, history_index, channel, energy)
    4419              :       INTEGER, INTENT(IN)                                :: vector_kind, history_index, channel
    4420              :       REAL(KIND=dp), DIMENSION(:), POINTER               :: energy
    4421              : 
    4422        13812 :          SELECT CASE (vector_kind)
    4423              :          CASE (broyden_position)
    4424         4380 :             CPASSERT(history_index > 0)
    4425         4380 :             energy => qs_ot_env(channel)%ener_h_x(history_index, :)
    4426              :          CASE (broyden_residual)
    4427         4548 :             CPASSERT(history_index > 0)
    4428         4548 :             energy => qs_ot_env(channel)%ener_h_e(history_index, :)
    4429              :          CASE (broyden_random)
    4430          392 :             energy => qs_ot_env(channel)%ener_x
    4431              :          CASE (broyden_gradient)
    4432          112 :             energy => qs_ot_env(channel)%ener_gx
    4433              :          CASE DEFAULT
    4434         9432 :             CPABORT("Invalid Broyden energy vector kind")
    4435              :          END SELECT
    4436         9432 :       END SUBROUTINE broyden_energy_pointer
    4437              : 
    4438              :    END SUBROUTINE ot_broyden_step
    4439              : 
    4440              : ! **************************************************************************************************
    4441              : !> \brief ...
    4442              : !> \param G ...
    4443              : !> \param S ...
    4444              : !> \param n ...
    4445              : !> \return ...
    4446              : ! **************************************************************************************************
    4447          180 :    FUNCTION new_sigma(G, S, n) RESULT(sigma)
    4448              : !
    4449              : ! Calculate new sigma from eigenvalues of full size G by Arnoldi.
    4450              : !
    4451              : ! **************************************************************************************************
    4452              : 
    4453              :       REAL(KIND=dp), DIMENSION(:, :)                     :: G, S
    4454              :       INTEGER                                            :: n
    4455              :       REAL(KIND=dp)                                      :: sigma
    4456              : 
    4457              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: eigv
    4458          180 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: H
    4459              : 
    4460          720 :       ALLOCATE (H(n, n))
    4461          180 :       CALL hess_G(G, S, H, n)
    4462          540 :       ALLOCATE (eigv(n))
    4463          180 :       CALL diamat_all(H(1:n, 1:n), eigv)
    4464              : 
    4465              :       SELECT CASE (1)
    4466              :       CASE (1)
    4467              :          ! This estimator seems to work well. No theory.
    4468         2240 :          sigma = SUM(ABS(eigv**2))/SUM(ABS(eigv))
    4469              :       CASE (2)
    4470              :          ! Estimator based on Frobenius norm minimizer
    4471              :          sigma = SUM(ABS(eigv))/MAX(1, SIZE(eigv))
    4472              :       CASE (3)
    4473              :          ! Estimator based on induced 2-norm
    4474              :          sigma = (MAXVAL(ABS(eigv)) + MINVAL(ABS(eigv)))*0.5_dp
    4475              :       END SELECT
    4476              : 
    4477          180 :       DEALLOCATE (H, eigv)
    4478          180 :    END FUNCTION new_sigma
    4479              : 
    4480              : ! **************************************************************************************************
    4481              : !> \brief ...
    4482              : !> \param G ...
    4483              : !> \param S ...
    4484              : !> \param H ...
    4485              : !> \param n ...
    4486              : ! **************************************************************************************************
    4487          180 :    SUBROUTINE hess_G(G, S, H, n)
    4488              : !
    4489              : ! Make a hessenberg out of G into H. Cf Arnoldi.
    4490              : ! Inner product is weighted by S.
    4491              : ! Possible lucky breakdown at n.
    4492              : !
    4493              : ! **************************************************************************************************
    4494              :       REAL(KIND=dp), DIMENSION(:, :)                     :: G, S, H
    4495              :       INTEGER                                            :: n
    4496              : 
    4497              :       INTEGER                                            :: i, j, k
    4498              :       REAL(KIND=dp)                                      :: tmp
    4499          180 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: v
    4500          180 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: Q
    4501              : 
    4502          180 :       i = SIZE(G, 1)
    4503          180 :       k = SIZE(H, 1)
    4504          720 :       ALLOCATE (Q(i, k))
    4505          540 :       ALLOCATE (v(i))
    4506         6944 :       H = 0.0_dp
    4507          180 :       Q = 0.0_dp
    4508              : 
    4509         2252 :       Q(:, 1) = 1.0_dp
    4510        31920 :       tmp = SQRT(DOT_PRODUCT(Q(:, 1), MATMUL(S, Q(:, 1))))
    4511        13708 :       Q(:, :) = Q(:, :)/tmp
    4512              : 
    4513         1114 :       DO i = 1, k
    4514       188308 :          v(:) = MATMUL(G, Q(:, i))
    4515         4280 :          DO j = 1, i
    4516       770712 :             H(j, i) = DOT_PRODUCT(Q(:, j), MATMUL(S, v))
    4517        50852 :             v(:) = v - H(j, i)*Q(:, j)
    4518              :          END DO
    4519         1114 :          IF (i < k) THEN
    4520       172308 :             tmp = DOT_PRODUCT(v, MATMUL(S, v))
    4521          766 :             IF (tmp <= 0.0_dp) THEN
    4522            4 :                n = i
    4523            4 :                EXIT
    4524              :             END IF
    4525          762 :             tmp = SQRT(tmp)
    4526              :             ! Lucky breakdown
    4527          762 :             IF (ABS(tmp) < 1e-9_dp) THEN
    4528            2 :                n = i
    4529            2 :                EXIT
    4530              :             END IF
    4531          760 :             H(i + 1, i) = tmp
    4532        11180 :             Q(:, i + 1) = v/H(i + 1, i)
    4533              :          END IF
    4534              :       END DO
    4535              : 
    4536          180 :       DEALLOCATE (Q, v)
    4537          180 :    END SUBROUTINE hess_G
    4538              : 
    4539         6584 : END MODULE qs_ot_minimizer
        

Generated by: LCOV version 2.0-1