LCOV - code coverage report
Current view: top level - src - qs_ot.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:123285f) Lines: 94.4 % 730 689
Test Date: 2026-11-04 00:58:17 Functions: 100.0 % 29 29

            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              : !>      Added Taylor expansion based computation of the matrix functions (01.2004)
      12              : !>      added additional rotation variables for non-equivalent occupied orbs (08.2004)
      13              : !> \author Joost VandeVondele (06.2002)
      14              : ! **************************************************************************************************
      15              : MODULE qs_ot
      16              :    USE arnoldi_api,                     ONLY: arnoldi_extremal
      17              :    USE cp_dbcsr_api,                    ONLY: &
      18              :         dbcsr_add, dbcsr_copy, dbcsr_create, dbcsr_distribution_type, dbcsr_filter, &
      19              :         dbcsr_finalize, dbcsr_get_block_p, dbcsr_get_info, dbcsr_get_occupation, dbcsr_init_p, &
      20              :         dbcsr_iterator_blocks_left, dbcsr_iterator_next_block, dbcsr_iterator_start, &
      21              :         dbcsr_iterator_stop, dbcsr_iterator_type, dbcsr_multiply, dbcsr_release, dbcsr_release_p, &
      22              :         dbcsr_reserve_blocks, dbcsr_scale, dbcsr_set, dbcsr_transposed, dbcsr_type, &
      23              :         dbcsr_type_no_symmetry
      24              :    USE cp_dbcsr_cholesky,               ONLY: cp_dbcsr_cholesky_decompose,&
      25              :                                               cp_dbcsr_cholesky_invert,&
      26              :                                               cp_dbcsr_cholesky_restore
      27              :    USE cp_dbcsr_contrib,                ONLY: dbcsr_add_on_diag,&
      28              :                                               dbcsr_frobenius_norm,&
      29              :                                               dbcsr_gershgorin_norm,&
      30              :                                               dbcsr_hadamard_product,&
      31              :                                               dbcsr_scale_by_vector
      32              :    USE cp_dbcsr_diag,                   ONLY: cp_dbcsr_heevd,&
      33              :                                               cp_dbcsr_syevd
      34              :    USE kinds,                           ONLY: dp
      35              :    USE message_passing,                 ONLY: mp_comm_type
      36              :    USE preconditioner,                  ONLY: apply_preconditioner
      37              :    USE preconditioner_types,            ONLY: preconditioner_type
      38              :    USE qs_ot_types,                     ONLY: qs_ot_type
      39              : #include "./base/base_uses.f90"
      40              : 
      41              :    IMPLICIT NONE
      42              :    PRIVATE
      43              : 
      44              :    PUBLIC :: qs_ot_get_p
      45              :    PUBLIC :: qs_ot_get_orbitals
      46              :    PUBLIC :: qs_ot_get_derivative
      47              :    PUBLIC :: qs_ot_project_gradient
      48              :    PUBLIC :: qs_ot_get_orbitals_ref
      49              :    PUBLIC :: qs_ot_get_derivative_ref
      50              :    PUBLIC :: qs_ot_generate_rotation
      51              :    PUBLIC :: qs_ot_rot_mat_derivative
      52              :    PUBLIC :: qs_ot_new_preconditioner
      53              :    PUBLIC :: qs_ot_complex_multiply
      54              :    PUBLIC :: qs_ot_p2m_diag
      55              :    PUBLIC :: qs_ot_ref_update
      56              :    PUBLIC :: qs_ot_spectral_kernel
      57              :    PUBLIC :: qs_ot_spectral_values
      58              :    PUBLIC :: qs_ot_square_transpose
      59              : 
      60              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_ot'
      61              : 
      62              : CONTAINS
      63              : 
      64              : ! **************************************************************************************************
      65              : !> \brief gets ready to use the preconditioner/ or renew the preconditioner
      66              : !>        only keeps a pointer to the preconditioner.
      67              : !>        If you change the preconditioner, you have to call this routine
      68              : !>        you remain responsible of proper deallocate of your preconditioner
      69              : !>        (or you can reuse it on the next step of the computation)
      70              : !> \param qs_ot_env ...
      71              : !> \param preconditioner ...
      72              : ! **************************************************************************************************
      73         9515 :    SUBROUTINE qs_ot_new_preconditioner(qs_ot_env, preconditioner)
      74              :       TYPE(qs_ot_type)                                   :: qs_ot_env
      75              :       TYPE(preconditioner_type), POINTER                 :: preconditioner
      76              : 
      77              :       INTEGER                                            :: ncoef
      78              : 
      79         9515 :       qs_ot_env%preconditioner => preconditioner
      80         9515 :       qs_ot_env%preconditioner_changed = .TRUE.
      81         9515 :       qs_ot_env%os_valid = .FALSE.
      82         9515 :       IF (.NOT. ASSOCIATED(qs_ot_env%matrix_psc0)) THEN
      83         9515 :          CALL dbcsr_init_p(qs_ot_env%matrix_psc0)
      84         9515 :          CALL dbcsr_copy(qs_ot_env%matrix_psc0, qs_ot_env%matrix_sc0, 'matrix_psc0')
      85              :       END IF
      86         9515 :       IF (qs_ot_env%has_complex_kpoint_state .AND. &
      87              :           .NOT. ASSOCIATED(qs_ot_env%matrix_psc0_im)) THEN
      88          749 :          CALL dbcsr_init_p(qs_ot_env%matrix_psc0_im)
      89          749 :          CALL dbcsr_copy(qs_ot_env%matrix_psc0_im, qs_ot_env%matrix_sc0_im, 'matrix_psc0_im')
      90              :       END IF
      91              : 
      92         9515 :       IF (.NOT. qs_ot_env%use_dx) THEN
      93         5775 :          qs_ot_env%use_dx = .TRUE.
      94         5775 :          CALL dbcsr_init_p(qs_ot_env%matrix_dx)
      95         5775 :          CALL dbcsr_copy(qs_ot_env%matrix_dx, qs_ot_env%matrix_gx, 'matrix_dx')
      96         5775 :          IF (qs_ot_env%has_complex_kpoint_state) THEN
      97          444 :             CALL dbcsr_init_p(qs_ot_env%matrix_dx_im)
      98          444 :             CALL dbcsr_copy(qs_ot_env%matrix_dx_im, qs_ot_env%matrix_gx_im, 'matrix_dx_im')
      99              :          END IF
     100         5775 :          IF (qs_ot_env%settings%do_rotation) THEN
     101           74 :             CALL dbcsr_init_p(qs_ot_env%rot_mat_dx)
     102           74 :             CALL dbcsr_copy(qs_ot_env%rot_mat_dx, qs_ot_env%rot_mat_gx, 'rot_mat_dx')
     103           74 :             IF (qs_ot_env%has_complex_kpoint_state) THEN
     104           48 :                CALL dbcsr_init_p(qs_ot_env%rot_mat_dx_im)
     105           48 :                CALL dbcsr_copy(qs_ot_env%rot_mat_dx_im, qs_ot_env%rot_mat_gx_im, 'rot_mat_dx_im')
     106              :             END IF
     107              :          END IF
     108         5775 :          IF (qs_ot_env%settings%do_ener) THEN
     109           40 :             ncoef = SIZE(qs_ot_env%ener_gx)
     110          120 :             ALLOCATE (qs_ot_env%ener_dx(ncoef))
     111          324 :             qs_ot_env%ener_dx = 0.0_dp
     112              :          END IF
     113              :       END IF
     114              : 
     115         9515 :    END SUBROUTINE qs_ot_new_preconditioner
     116              : 
     117              : ! **************************************************************************************************
     118              : !> \brief multiply paired real/imaginary DBCSR matrices, with optional conjugate transposes
     119              : !> \param op_a N or C
     120              : !> \param op_b N or C
     121              : !> \param a_re real part of A
     122              : !> \param a_im imaginary part of A
     123              : !> \param b_re real part of B
     124              : !> \param b_im imaginary part of B
     125              : !> \param c_re real part of A*B
     126              : !> \param c_im imaginary part of A*B
     127              : !> \param tmp real workspace shaped like C
     128              : ! **************************************************************************************************
     129        42726 :    SUBROUTINE qs_ot_complex_multiply(op_a, op_b, a_re, a_im, b_re, b_im, c_re, c_im, tmp)
     130              :       CHARACTER(LEN=1), INTENT(IN)                       :: op_a, op_b
     131              :       TYPE(dbcsr_type)                                   :: a_re, a_im, b_re, b_im, c_re, c_im, tmp
     132              : 
     133              :       CHARACTER(LEN=1)                                   :: db_op_a, db_op_b
     134              :       REAL(KIND=dp)                                      :: sign_a, sign_b
     135              : 
     136        42726 :       IF (op_a /= 'N' .AND. op_a /= 'C') THEN
     137            0 :          CPABORT("Complex matrix product expects N or C for op_a")
     138              :       END IF
     139        42726 :       IF (op_b /= 'N' .AND. op_b /= 'C') THEN
     140            0 :          CPABORT("Complex matrix product expects N or C for op_b")
     141              :       END IF
     142        42726 :       db_op_a = MERGE('N', 'T', op_a == 'N')
     143        42726 :       db_op_b = MERGE('N', 'T', op_b == 'N')
     144        42726 :       sign_a = MERGE(1.0_dp, -1.0_dp, op_a == 'N')
     145        42726 :       sign_b = MERGE(1.0_dp, -1.0_dp, op_b == 'N')
     146              : 
     147        42726 :       CALL dbcsr_multiply(db_op_a, db_op_b, 1.0_dp, a_re, b_re, 0.0_dp, c_re)
     148        42726 :       CALL dbcsr_multiply(db_op_a, db_op_b, 1.0_dp, a_im, b_im, 0.0_dp, tmp)
     149        42726 :       CALL dbcsr_add(c_re, tmp, alpha_scalar=1.0_dp, beta_scalar=-sign_a*sign_b)
     150              : 
     151        42726 :       CALL dbcsr_multiply(db_op_a, db_op_b, sign_b, a_re, b_im, 0.0_dp, c_im)
     152        42726 :       CALL dbcsr_multiply(db_op_a, db_op_b, sign_a, a_im, b_re, 0.0_dp, tmp)
     153        42726 :       CALL dbcsr_add(c_im, tmp, alpha_scalar=1.0_dp, beta_scalar=1.0_dp)
     154              : 
     155        42726 :    END SUBROUTINE qs_ot_complex_multiply
     156              : 
     157              : ! **************************************************************************************************
     158              : !> \brief ...
     159              : !> \param qs_ot_env ...
     160              : !> \param C_NEW ...
     161              : !> \param SC ...
     162              : !> \param G_OLD ...
     163              : !> \param D ...
     164              : ! **************************************************************************************************
     165          840 :    SUBROUTINE qs_ot_on_the_fly_localize(qs_ot_env, C_NEW, SC, G_OLD, D)
     166              :       !
     167              :       TYPE(qs_ot_type)                                   :: qs_ot_env
     168              :       TYPE(dbcsr_type), POINTER                          :: C_NEW, SC, G_OLD, D
     169              : 
     170              :       CHARACTER(len=*), PARAMETER :: routineN = 'qs_ot_on_the_fly_localize'
     171              :       INTEGER, PARAMETER                                 :: taylor_order = 50
     172              :       REAL(KIND=dp), PARAMETER                           :: alpha = 0.1_dp, f2_eps = 0.01_dp
     173              : 
     174              :       INTEGER                                            :: col, col_size, handle, i, k, n, p, row, &
     175              :                                                             row_size
     176          168 :       REAL(dp), DIMENSION(:, :), POINTER                 :: block
     177              :       REAL(KIND=dp)                                      :: expfactor, f2, norm_fro, norm_gct, tmp
     178              :       TYPE(dbcsr_distribution_type)                      :: dist
     179              :       TYPE(dbcsr_iterator_type)                          :: iter
     180              :       TYPE(dbcsr_type), POINTER                          :: C, Gp1, Gp2, GU, U
     181              :       TYPE(mp_comm_type)                                 :: group
     182              : 
     183          168 :       CALL timeset(routineN, handle)
     184              :       !
     185              :       !
     186          168 :       CALL dbcsr_get_info(C_NEW, nfullrows_total=n, nfullcols_total=k)
     187              :       !
     188              :       ! C = C*expm(-G)
     189          168 :       GU => qs_ot_env%buf1_k_k_nosym ! a buffer
     190          168 :       U => qs_ot_env%buf2_k_k_nosym ! a buffer
     191          168 :       Gp1 => qs_ot_env%buf3_k_k_nosym ! a buffer
     192          168 :       Gp2 => qs_ot_env%buf4_k_k_nosym ! a buffer
     193          168 :       C => qs_ot_env%buf1_n_k ! a buffer
     194              :       !
     195              :       ! compute the derivative of the norm
     196              :       !-------------------------------------------------------------------
     197              :       ! (x^2+eps)^1/2
     198          168 :       f2 = 0.0_dp
     199          168 :       CALL dbcsr_copy(C, C_NEW)
     200          168 :       CALL dbcsr_iterator_start(iter, C)
     201          392 :       DO WHILE (dbcsr_iterator_blocks_left(iter))
     202          224 :          CALL dbcsr_iterator_next_block(iter, row, col, block, row_size=row_size, col_size=col_size)
     203         1400 :          DO p = 1, col_size ! p
     204         9912 :          DO i = 1, row_size ! i
     205         8680 :             tmp = SQRT(block(i, p)**2 + f2_eps)
     206         8680 :             f2 = f2 + tmp
     207         9688 :             block(i, p) = block(i, p)/tmp
     208              :          END DO
     209              :          END DO
     210              :       END DO
     211          168 :       CALL dbcsr_iterator_stop(iter)
     212          168 :       CALL dbcsr_get_info(C, group=group)
     213          168 :       CALL group%sum(f2)
     214              :       !
     215              :       !
     216          168 :       CALL dbcsr_multiply('T', 'N', 1.0_dp, C, C_NEW, 0.0_dp, GU)
     217              :       !
     218              :       ! antisymetrize
     219          168 :       CALL dbcsr_get_info(GU, distribution=dist)
     220              :       CALL dbcsr_transposed(U, GU, shallow_data_copy=.FALSE., &
     221              :                             use_distribution=dist, &
     222          168 :                             transpose_distribution=.FALSE.)
     223          168 :       CALL dbcsr_add(GU, U, alpha_scalar=-0.5_dp, beta_scalar=0.5_dp)
     224              :       !-------------------------------------------------------------------
     225              :       !
     226          168 :       norm_fro = dbcsr_frobenius_norm(GU)
     227          168 :       norm_gct = dbcsr_gershgorin_norm(GU)
     228              :       !write(*,*) 'qs_ot_localize: ||P-I||_f=',norm_fro,' ||P-I||_GCT=',norm_gct
     229              :       !
     230              :       !kscale = CEILING(LOG(MIN(norm_fro,norm_gct))/LOG(2.0_dp))
     231              :       !scale  = LOG(MIN(norm_fro,norm_gct))/LOG(2.0_dp)
     232              :       !write(*,*) 'qs_ot_localize: scale=',scale,' kscale=',kscale
     233              :       !
     234              :       ! rescale for steepest descent
     235          168 :       CALL dbcsr_scale(GU, -alpha)
     236              :       !
     237              :       ! compute unitary transform
     238              :       ! zeroth and first order
     239          168 :       expfactor = 1.0_dp
     240          168 :       CALL dbcsr_copy(U, GU)
     241          168 :       CALL dbcsr_scale(U, expfactor)
     242          168 :       CALL dbcsr_add_on_diag(U, 1.0_dp)
     243              :       ! other orders
     244          168 :       CALL dbcsr_copy(Gp1, GU)
     245          806 :       DO i = 2, taylor_order
     246              :          ! new power of G
     247          806 :          CALL dbcsr_multiply('N', 'N', 1.0_dp, GU, Gp1, 0.0_dp, Gp2)
     248          806 :          CALL dbcsr_copy(Gp1, Gp2)
     249              :          ! add to the taylor expansion so far
     250          806 :          expfactor = expfactor/REAL(i, KIND=dp)
     251          806 :          CALL dbcsr_add(U, Gp1, alpha_scalar=1.0_dp, beta_scalar=expfactor)
     252          806 :          norm_fro = dbcsr_frobenius_norm(Gp1)
     253              :          !write(*,*) 'Taylor expansion i=',i,' norm(X^i)/i!=',norm_fro*expfactor
     254          806 :          IF (norm_fro*expfactor < 1.0E-10_dp) EXIT
     255              :       END DO
     256              :       !
     257              :       ! rotate MOs
     258          168 :       CALL dbcsr_multiply('N', 'N', 1.0_dp, C_NEW, U, 0.0_dp, C)
     259          168 :       CALL dbcsr_copy(C_NEW, C)
     260              :       !
     261              :       ! rotate SC
     262          168 :       CALL dbcsr_multiply('N', 'N', 1.0_dp, SC, U, 0.0_dp, C)
     263          168 :       CALL dbcsr_copy(SC, C)
     264              :       !
     265              :       ! rotate D_i
     266          168 :       CALL dbcsr_multiply('N', 'N', 1.0_dp, D, U, 0.0_dp, C)
     267          168 :       CALL dbcsr_copy(D, C)
     268              :       !
     269              :       ! rotate G_i-1
     270          168 :       IF (ASSOCIATED(G_OLD)) THEN
     271          168 :          CALL dbcsr_multiply('N', 'N', 1.0_dp, G_OLD, U, 0.0_dp, C)
     272          168 :          CALL dbcsr_copy(G_OLD, C)
     273              :       END IF
     274              :       !
     275          168 :       CALL timestop(handle)
     276          168 :    END SUBROUTINE qs_ot_on_the_fly_localize
     277              : 
     278              : ! **************************************************************************************************
     279              : !> \brief ...
     280              : !> \param qs_ot_env ...
     281              : !> \param C_OLD ...
     282              : !> \param C_TMP ...
     283              : !> \param C_NEW ...
     284              : !> \param P ...
     285              : !> \param SC ...
     286              : !> \param update ...
     287              : ! **************************************************************************************************
     288         1736 :    SUBROUTINE qs_ot_ref_chol(qs_ot_env, C_OLD, C_TMP, C_NEW, P, SC, update)
     289              :       !
     290              :       TYPE(qs_ot_type)                                   :: qs_ot_env
     291              :       TYPE(dbcsr_type)                                   :: C_OLD, C_TMP, C_NEW, P, SC
     292              :       LOGICAL, INTENT(IN)                                :: update
     293              : 
     294              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'qs_ot_ref_chol'
     295              : 
     296              :       INTEGER                                            :: handle, k, n
     297              : 
     298          868 :       CALL timeset(routineN, handle)
     299              :       !
     300          868 :       CALL dbcsr_get_info(C_NEW, nfullrows_total=n, nfullcols_total=k)
     301              :       !
     302              :       ! P = U'*U
     303          868 :       CALL cp_dbcsr_cholesky_decompose(P, k, qs_ot_env%para_env, qs_ot_env%blacs_env)
     304              :       !
     305              :       ! C_NEW = C_OLD*inv(U)
     306              :       CALL cp_dbcsr_cholesky_restore(C_OLD, k, P, C_NEW, op="SOLVE", pos="RIGHT", &
     307          868 :                                      transa="N", para_env=qs_ot_env%para_env, blacs_env=qs_ot_env%blacs_env)
     308              :       !
     309              :       ! Update SC if needed
     310          868 :       IF (update) THEN
     311              :          CALL cp_dbcsr_cholesky_restore(SC, k, P, C_TMP, op="SOLVE", pos="RIGHT", &
     312          472 :                                         transa="N", para_env=qs_ot_env%para_env, blacs_env=qs_ot_env%blacs_env)
     313          472 :          CALL dbcsr_copy(SC, C_TMP)
     314              :       END IF
     315              :       !
     316          868 :       CALL timestop(handle)
     317          868 :    END SUBROUTINE qs_ot_ref_chol
     318              : 
     319              : ! **************************************************************************************************
     320              : !> \brief ...
     321              : !> \param qs_ot_env ...
     322              : !> \param C_OLD ...
     323              : !> \param C_TMP ...
     324              : !> \param C_NEW ...
     325              : !> \param P ...
     326              : !> \param SC ...
     327              : !> \param update ...
     328              : ! **************************************************************************************************
     329          478 :    SUBROUTINE qs_ot_ref_lwdn(qs_ot_env, C_OLD, C_TMP, C_NEW, P, SC, update)
     330              :       !
     331              :       TYPE(qs_ot_type)                                   :: qs_ot_env
     332              :       TYPE(dbcsr_type)                                   :: C_OLD, C_TMP, C_NEW, P, SC
     333              :       LOGICAL, INTENT(IN)                                :: update
     334              : 
     335              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'qs_ot_ref_lwdn'
     336              : 
     337              :       INTEGER                                            :: handle, i, k, n
     338              :       REAL(dp), ALLOCATABLE, DIMENSION(:)                :: eig, fun
     339              :       TYPE(dbcsr_type), POINTER                          :: V, W
     340              : 
     341          478 :       CALL timeset(routineN, handle)
     342              :       !
     343          478 :       CALL dbcsr_get_info(C_NEW, nfullrows_total=n, nfullcols_total=k)
     344              :       !
     345          478 :       V => qs_ot_env%buf1_k_k_nosym ! a buffer
     346          478 :       W => qs_ot_env%buf2_k_k_nosym ! a buffer
     347         1912 :       ALLOCATE (eig(k), fun(k))
     348              :       !
     349          478 :       CALL cp_dbcsr_syevd(P, V, eig, qs_ot_env%para_env, qs_ot_env%blacs_env)
     350              :       !
     351              :       ! compute the P^(-1/2)
     352         2646 :       DO i = 1, k
     353         2168 :          IF (eig(i) <= 0.0_dp) THEN
     354            0 :             CPABORT("P not positive definite")
     355              :          END IF
     356         2646 :          IF (eig(i) < 1.0E-8_dp) THEN
     357            0 :             fun(i) = 0.0_dp
     358              :          ELSE
     359         2168 :             fun(i) = 1.0_dp/SQRT(eig(i))
     360              :          END IF
     361              :       END DO
     362          478 :       CALL dbcsr_copy(W, V)
     363          478 :       CALL dbcsr_scale_by_vector(V, alpha=fun, side='right')
     364          478 :       CALL dbcsr_multiply('N', 'T', 1.0_dp, W, V, 0.0_dp, P)
     365              :       !
     366              :       ! Update C
     367          478 :       CALL dbcsr_multiply('N', 'N', 1.0_dp, C_OLD, P, 0.0_dp, C_NEW)
     368              :       !
     369              :       ! Update SC if needed
     370          478 :       IF (update) THEN
     371          300 :          CALL dbcsr_multiply('N', 'N', 1.0_dp, SC, P, 0.0_dp, C_TMP)
     372          300 :          CALL dbcsr_copy(SC, C_TMP)
     373              :       END IF
     374              :       !
     375          478 :       DEALLOCATE (eig, fun)
     376              :       !
     377          478 :       CALL timestop(handle)
     378          478 :    END SUBROUTINE qs_ot_ref_lwdn
     379              : 
     380              : ! **************************************************************************************************
     381              : !> \brief ...
     382              : !> \param qs_ot_env ...
     383              : !> \param C_OLD ...
     384              : !> \param C_TMP ...
     385              : !> \param C_NEW ...
     386              : !> \param P ...
     387              : !> \param SC ...
     388              : !> \param norm_in ...
     389              : !> \param update ...
     390              : ! **************************************************************************************************
     391         8560 :    SUBROUTINE qs_ot_ref_poly(qs_ot_env, C_OLD, C_TMP, C_NEW, P, SC, norm_in, update)
     392              :       !
     393              :       TYPE(qs_ot_type)                                   :: qs_ot_env
     394              :       TYPE(dbcsr_type), POINTER                          :: C_OLD, C_TMP, C_NEW, P
     395              :       TYPE(dbcsr_type)                                   :: SC
     396              :       REAL(dp), INTENT(IN)                               :: norm_in
     397              :       LOGICAL, INTENT(IN)                                :: update
     398              : 
     399              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'qs_ot_ref_poly'
     400              : 
     401              :       INTEGER                                            :: handle, irefine, k, n
     402              :       LOGICAL                                            :: quick_exit
     403              :       REAL(dp)                                           :: norm, norm_fro, norm_gct, occ_in, &
     404              :                                                             occ_out, rescale
     405              :       TYPE(dbcsr_type), POINTER                          :: BUF1, BUF2, BUF_NOSYM, FT, FY
     406              : 
     407         4280 :       CALL timeset(routineN, handle)
     408              :       !
     409         4280 :       CALL dbcsr_get_info(C_NEW, nfullrows_total=n, nfullcols_total=k)
     410              :       !
     411         4280 :       BUF_NOSYM => qs_ot_env%buf1_k_k_nosym ! a buffer
     412         4280 :       BUF1 => qs_ot_env%buf1_k_k_sym ! a buffer
     413         4280 :       BUF2 => qs_ot_env%buf2_k_k_sym ! a buffer
     414         4280 :       FY => qs_ot_env%buf3_k_k_sym ! a buffer
     415         4280 :       FT => qs_ot_env%buf4_k_k_sym ! a buffer
     416              :       !
     417              :       ! initialize the norm (already computed in qs_ot_get_orbitals_ref)
     418         4280 :       norm = norm_in
     419              :       !
     420              :       ! can we do a quick exit?
     421         4280 :       quick_exit = .FALSE.
     422         4280 :       IF (norm < qs_ot_env%settings%eps_irac_quick_exit) quick_exit = .TRUE.
     423              :       !
     424              :       ! lets refine
     425         4280 :       rescale = 1.0_dp
     426         4714 :       DO irefine = 1, qs_ot_env%settings%max_irac
     427              :          !
     428              :          ! rescaling
     429         4714 :          IF (norm > 1.0_dp) THEN
     430           12 :             CALL dbcsr_scale(P, 1.0_dp/norm)
     431           12 :             rescale = rescale/SQRT(norm)
     432              :          END IF
     433              :          !
     434              :          ! get the refinement polynomial
     435              :          CALL qs_ot_refine(P, FY, BUF1, BUF2, qs_ot_env%settings%irac_degree, &
     436         4714 :                            qs_ot_env%settings%eps_irac_filter_matrix)
     437              :          !
     438              :          ! collect the transformation
     439         4714 :          IF (irefine == 1) THEN
     440         4280 :             CALL dbcsr_copy(FT, FY, name='FT')
     441              :          ELSE
     442          434 :             CALL dbcsr_multiply('N', 'N', 1.0_dp, FT, FY, 0.0_dp, BUF1)
     443          434 :             IF (qs_ot_env%settings%eps_irac_filter_matrix > 0.0_dp) THEN
     444            4 :                occ_in = dbcsr_get_occupation(buf1)
     445            4 :                CALL dbcsr_filter(buf1, qs_ot_env%settings%eps_irac_filter_matrix)
     446            4 :                occ_out = dbcsr_get_occupation(buf1)
     447              :             END IF
     448          434 :             CALL dbcsr_copy(FT, BUF1, name='FT')
     449              :          END IF
     450              :          !
     451              :          ! quick exit if possible
     452         4714 :          IF (quick_exit) THEN
     453              :             EXIT
     454              :          END IF
     455              :          !
     456              :          ! P = FY^T * P * FY
     457         2036 :          CALL dbcsr_multiply('N', 'N', 1.0_dp, P, FY, 0.0_dp, BUF_NOSYM)
     458         2036 :          IF (qs_ot_env%settings%eps_irac_filter_matrix > 0.0_dp) THEN
     459            8 :             occ_in = dbcsr_get_occupation(buf_nosym)
     460            8 :             CALL dbcsr_filter(buf_nosym, qs_ot_env%settings%eps_irac_filter_matrix)
     461            8 :             occ_out = dbcsr_get_occupation(buf_nosym)
     462              :          END IF
     463         2036 :          CALL dbcsr_multiply('N', 'N', 1.0_dp, FY, BUF_NOSYM, 0.0_dp, P)
     464         2036 :          IF (qs_ot_env%settings%eps_irac_filter_matrix > 0.0_dp) THEN
     465            8 :             occ_in = dbcsr_get_occupation(p)
     466            8 :             CALL dbcsr_filter(p, qs_ot_env%settings%eps_irac_filter_matrix)
     467            8 :             occ_out = dbcsr_get_occupation(p)
     468              :          END IF
     469              :          !
     470              :          ! check ||P-1||_gct
     471         2036 :          CALL dbcsr_add_on_diag(P, -1.0_dp)
     472         2036 :          norm_fro = dbcsr_frobenius_norm(P)
     473         2036 :          norm_gct = dbcsr_gershgorin_norm(P)
     474         2036 :          CALL dbcsr_add_on_diag(P, 1.0_dp)
     475         2036 :          norm = MIN(norm_gct, norm_fro)
     476              :          !
     477              :          ! printing
     478              :          !
     479              :          ! blows up
     480         2036 :          IF (norm > 1.0E10_dp) THEN
     481              :             CALL cp_abort(__LOCATION__, &
     482              :                           "Refinement blows up! "// &
     483              :                           "We need you to improve the code, please post your input on "// &
     484            0 :                           "the forum https://www.cp2k.org/")
     485              :          END IF
     486              :          !
     487              :          ! can we do a quick exit next step?
     488         2036 :          IF (norm < qs_ot_env%settings%eps_irac_quick_exit) quick_exit = .TRUE.
     489              :          !
     490              :          ! are we done?
     491         4714 :          IF (norm < qs_ot_env%settings%eps_irac) EXIT
     492              :          !
     493              :       END DO
     494              :       !
     495              :       ! C_NEW = C_NEW * FT * rescale
     496         4280 :       CALL dbcsr_multiply('N', 'N', rescale, C_OLD, FT, 0.0_dp, C_NEW)
     497         4280 :       IF (qs_ot_env%settings%eps_irac_filter_matrix > 0.0_dp) THEN
     498            4 :          occ_in = dbcsr_get_occupation(c_new)
     499            4 :          CALL dbcsr_filter(c_new, qs_ot_env%settings%eps_irac_filter_matrix)
     500            4 :          occ_out = dbcsr_get_occupation(c_new)
     501              :       END IF
     502              :       !
     503              :       ! update SC = SC * FY * rescale
     504         4280 :       IF (update) THEN
     505         1754 :          CALL dbcsr_multiply('N', 'N', rescale, SC, FT, 0.0_dp, C_TMP)
     506         1754 :          IF (qs_ot_env%settings%eps_irac_filter_matrix > 0.0_dp) THEN
     507            4 :             occ_in = dbcsr_get_occupation(c_tmp)
     508            4 :             CALL dbcsr_filter(c_tmp, qs_ot_env%settings%eps_irac_filter_matrix)
     509            4 :             occ_out = dbcsr_get_occupation(c_tmp)
     510              :          END IF
     511         1754 :          CALL dbcsr_copy(SC, C_TMP)
     512              :       END IF
     513              :       !
     514         4280 :       CALL timestop(handle)
     515         4280 :    END SUBROUTINE qs_ot_ref_poly
     516              : 
     517              : ! **************************************************************************************************
     518              : !> \brief ...
     519              : !> \param qs_ot_env1 ...
     520              : !> \return ...
     521              : ! **************************************************************************************************
     522         8344 :    FUNCTION qs_ot_ref_update(qs_ot_env1) RESULT(update)
     523              :       !
     524              :       TYPE(qs_ot_type)                                   :: qs_ot_env1
     525              :       LOGICAL                                            :: update
     526              : 
     527         8344 :       update = .FALSE.
     528         6802 :       SELECT CASE (qs_ot_env1%settings%ot_method)
     529              :       CASE ("CG", "SD")
     530         6802 :          SELECT CASE (qs_ot_env1%settings%line_search_method)
     531              :          CASE ("2PNT")
     532         6802 :             IF (qs_ot_env1%line_search_count == 2) update = .TRUE.
     533              :          CASE DEFAULT
     534         6802 :             CPABORT("NYI")
     535              :          END SELECT
     536              :       CASE ("DIIS")
     537          628 :          update = .TRUE.
     538              :       CASE ("BROY", "LBFG")
     539              :          ! These minimizers retain positions or secants in one fixed REF chart.
     540          628 :          update = .FALSE.
     541              :       CASE DEFAULT
     542         8344 :          CPABORT("NYI")
     543              :       END SELECT
     544         8344 :    END FUNCTION qs_ot_ref_update
     545              : 
     546              : ! **************************************************************************************************
     547              : !> \brief ...
     548              : !> \param qs_ot_env1 ...
     549              : !> \param norm_in ...
     550              : !> \param ortho_irac ...
     551              : ! **************************************************************************************************
     552         5626 :    SUBROUTINE qs_ot_ref_decide(qs_ot_env1, norm_in, ortho_irac)
     553              :       !
     554              :       TYPE(qs_ot_type)                                   :: qs_ot_env1
     555              :       REAL(dp), INTENT(IN)                               :: norm_in
     556              :       CHARACTER(LEN=*), INTENT(INOUT)                    :: ortho_irac
     557              : 
     558         5626 :       ortho_irac = qs_ot_env1%settings%ortho_irac
     559         5626 :       IF (norm_in < qs_ot_env1%settings%eps_irac_switch) ortho_irac = "POLY"
     560         5626 :    END SUBROUTINE qs_ot_ref_decide
     561              : 
     562              : ! **************************************************************************************************
     563              : !> \brief ...
     564              : !> \param matrix_c ...
     565              : !> \param matrix_s ...
     566              : !> \param matrix_x ...
     567              : !> \param matrix_sx ...
     568              : !> \param matrix_gx_old ...
     569              : !> \param matrix_dx ...
     570              : !> \param qs_ot_env ...
     571              : !> \param qs_ot_env1 ...
     572              : ! **************************************************************************************************
     573        11252 :    SUBROUTINE qs_ot_get_orbitals_ref(matrix_c, matrix_s, matrix_x, matrix_sx, &
     574              :                                      matrix_gx_old, matrix_dx, qs_ot_env, qs_ot_env1)
     575              :       !
     576              :       TYPE(dbcsr_type), POINTER                          :: matrix_c, matrix_s, matrix_x, matrix_sx, &
     577              :                                                             matrix_gx_old, matrix_dx
     578              :       TYPE(qs_ot_type)                                   :: qs_ot_env, qs_ot_env1
     579              : 
     580              :       CHARACTER(len=*), PARAMETER :: routineN = 'qs_ot_get_orbitals_ref'
     581              : 
     582              :       CHARACTER(LEN=4)                                   :: ortho_irac
     583              :       INTEGER                                            :: handle, k, n
     584              :       LOGICAL                                            :: on_the_fly_loc, update
     585              :       REAL(dp)                                           :: norm, norm_fro, norm_gct, occ_in, occ_out
     586              :       TYPE(dbcsr_type), POINTER                          :: C_NEW, C_OLD, C_TMP, D, G_OLD, P, S, SC
     587              : 
     588         5626 :       CALL timeset(routineN, handle)
     589              : 
     590         5626 :       CALL dbcsr_get_info(matrix_c, nfullrows_total=n, nfullcols_total=k)
     591              :       !
     592         5626 :       C_NEW => matrix_c
     593         5626 :       C_OLD => matrix_x ! need to be carefully updated for the gradient !
     594         5626 :       SC => matrix_sx ! need to be carefully updated for the gradient !
     595         5626 :       G_OLD => matrix_gx_old ! need to be carefully updated for localization !
     596         5626 :       D => matrix_dx ! need to be carefully updated for localization !
     597         5626 :       S => matrix_s
     598              : 
     599         5626 :       P => qs_ot_env%p_k_k_sym ! a buffer
     600         5626 :       C_TMP => qs_ot_env%buf1_n_k ! a buffer
     601              :       !
     602              :       ! do we need to update C_OLD and SC?
     603         5626 :       update = qs_ot_ref_update(qs_ot_env1)
     604              :       !
     605              :       ! do we want to on the fly localize?
     606              :       ! for the moment this is set from the input,
     607              :       ! later we might want to localize every n-step or
     608              :       ! when the sparsity increases...
     609         5626 :       on_the_fly_loc = qs_ot_env1%settings%on_the_fly_loc
     610              :       !
     611              :       ! compute SC = S*C
     612         5626 :       IF (ASSOCIATED(S)) THEN
     613         5626 :          CALL dbcsr_multiply('N', 'N', 1.0_dp, S, C_OLD, 0.0_dp, SC)
     614         5626 :          IF (qs_ot_env1%settings%eps_irac_filter_matrix > 0.0_dp) THEN
     615            4 :             occ_in = dbcsr_get_occupation(sc)
     616            4 :             CALL dbcsr_filter(sc, qs_ot_env1%settings%eps_irac_filter_matrix)
     617            4 :             occ_out = dbcsr_get_occupation(sc)
     618              :          END IF
     619              :       ELSE
     620            0 :          CALL dbcsr_copy(SC, C_OLD)
     621              :       END IF
     622              :       !
     623              :       ! compute P = C'*SC
     624         5626 :       CALL dbcsr_multiply('T', 'N', 1.0_dp, C_OLD, SC, 0.0_dp, P)
     625         5626 :       IF (qs_ot_env1%settings%eps_irac_filter_matrix > 0.0_dp) THEN
     626            4 :          occ_in = dbcsr_get_occupation(p)
     627            4 :          CALL dbcsr_filter(p, qs_ot_env1%settings%eps_irac_filter_matrix)
     628            4 :          occ_out = dbcsr_get_occupation(p)
     629              :       END IF
     630              :       !
     631              :       ! check ||P-1||_f and ||P-1||_gct
     632         5626 :       CALL dbcsr_add_on_diag(P, -1.0_dp)
     633         5626 :       norm_fro = dbcsr_frobenius_norm(P)
     634         5626 :       norm_gct = dbcsr_gershgorin_norm(P)
     635         5626 :       CALL dbcsr_add_on_diag(P, 1.0_dp)
     636         5626 :       norm = MIN(norm_gct, norm_fro)
     637         5626 :       CALL qs_ot_ref_decide(qs_ot_env1, norm, ortho_irac)
     638              :       !
     639              :       ! select the orthogonality method
     640          868 :       SELECT CASE (ortho_irac)
     641              :       CASE ("CHOL")
     642          868 :          CALL qs_ot_ref_chol(qs_ot_env, C_OLD, C_TMP, C_NEW, P, SC, update)
     643              :       CASE ("LWDN")
     644          478 :          CALL qs_ot_ref_lwdn(qs_ot_env, C_OLD, C_TMP, C_NEW, P, SC, update)
     645              :       CASE ("POLY")
     646         4280 :          CALL qs_ot_ref_poly(qs_ot_env, C_OLD, C_TMP, C_NEW, P, SC, norm, update)
     647              :       CASE DEFAULT
     648         5626 :          CPABORT("Wrong argument")
     649              :       END SELECT
     650              :       !
     651              :       ! We update the C_i+1 and localization
     652         5626 :       IF (update) THEN
     653         2526 :          IF (on_the_fly_loc) THEN
     654          168 :             CALL qs_ot_on_the_fly_localize(qs_ot_env, C_NEW, SC, G_OLD, D)
     655              :          END IF
     656         2526 :          CALL dbcsr_copy(C_OLD, C_NEW)
     657              :       END IF
     658              : 
     659         5626 :       IF (qs_ot_env%settings%do_rotation) THEN
     660           14 :          CALL qs_ot_generate_rotation(qs_ot_env)
     661              :          CALL dbcsr_multiply('N', 'N', 1.0_dp, C_NEW, qs_ot_env%rot_mat_u, &
     662           14 :                              0.0_dp, C_TMP)
     663           14 :          CALL dbcsr_copy(C_NEW, C_TMP)
     664              :       END IF
     665              :       !
     666         5626 :       CALL timestop(handle)
     667         5626 :    END SUBROUTINE qs_ot_get_orbitals_ref
     668              : 
     669              : ! **************************************************************************************************
     670              : !> \brief  refinement polynomial of degree 2,3 and 4 (PRB 70, 193102 (2004))
     671              : !> \param P ...
     672              : !> \param FY ...
     673              : !> \param P2 ...
     674              : !> \param T ...
     675              : !> \param irac_degree ...
     676              : !> \param eps_irac_filter_matrix ...
     677              : ! **************************************************************************************************
     678         9428 :    SUBROUTINE qs_ot_refine(P, FY, P2, T, irac_degree, eps_irac_filter_matrix)
     679              :       TYPE(dbcsr_type), INTENT(inout)                    :: P, FY, P2, T
     680              :       INTEGER, INTENT(in)                                :: irac_degree
     681              :       REAL(dp), INTENT(in)                               :: eps_irac_filter_matrix
     682              : 
     683              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'qs_ot_refine'
     684              : 
     685              :       INTEGER                                            :: handle, k
     686              :       REAL(dp)                                           :: occ_in, occ_out, r
     687              : 
     688         4714 :       CALL timeset(routineN, handle)
     689              : 
     690         4714 :       CALL dbcsr_get_info(P, nfullcols_total=k)
     691         4714 :       SELECT CASE (irac_degree)
     692              :       CASE (2)
     693              :          ! C_out = C_in * ( 15/8 * I - 10/8 * P + 3/8 * P^2)
     694            0 :          r = 3.0_dp/8.0_dp
     695            0 :          CALL dbcsr_multiply('N', 'N', r, P, P, 0.0_dp, FY)
     696            0 :          IF (eps_irac_filter_matrix > 0.0_dp) THEN
     697            0 :             occ_in = dbcsr_get_occupation(fy)
     698            0 :             CALL dbcsr_filter(fy, eps_irac_filter_matrix)
     699            0 :             occ_out = dbcsr_get_occupation(fy)
     700              :          END IF
     701            0 :          r = -10.0_dp/8.0_dp
     702            0 :          CALL dbcsr_add(FY, P, alpha_scalar=1.0_dp, beta_scalar=r)
     703            0 :          r = 15.0_dp/8.0_dp
     704            0 :          CALL dbcsr_add_on_diag(FY, alpha=r)
     705              :       CASE (3)
     706              :          ! C_out = C_in * ( 35/16 * I - 35/16 * P + 21/16 * P^2 - 5/16 P^3)
     707            0 :          CALL dbcsr_multiply('N', 'N', 1.0_dp, P, P, 0.0_dp, P2)
     708            0 :          IF (eps_irac_filter_matrix > 0.0_dp) THEN
     709            0 :             occ_in = dbcsr_get_occupation(p2)
     710            0 :             CALL dbcsr_filter(p2, eps_irac_filter_matrix)
     711            0 :             occ_out = dbcsr_get_occupation(p2)
     712              :          END IF
     713            0 :          r = -5.0_dp/16.0_dp
     714            0 :          CALL dbcsr_multiply('N', 'N', r, P2, P, 0.0_dp, FY)
     715            0 :          IF (eps_irac_filter_matrix > 0.0_dp) THEN
     716            0 :             occ_in = dbcsr_get_occupation(fy)
     717            0 :             CALL dbcsr_filter(fy, eps_irac_filter_matrix)
     718            0 :             occ_out = dbcsr_get_occupation(fy)
     719              :          END IF
     720            0 :          r = 21.0_dp/16.0_dp
     721            0 :          CALL dbcsr_add(FY, P2, alpha_scalar=1.0_dp, beta_scalar=r)
     722            0 :          r = -35.0_dp/16.0_dp
     723            0 :          CALL dbcsr_add(FY, P, alpha_scalar=1.0_dp, beta_scalar=r)
     724            0 :          r = 35.0_dp/16.0_dp
     725            0 :          CALL dbcsr_add_on_diag(FY, alpha=r)
     726              :       CASE (4)
     727              :          ! C_out = C_in * ( 315/128 * I - 420/128 * P + 378/128 * P^2 - 180/128 P^3 + 35/128 P^4 )
     728              :          !       = C_in * ( 315/128 * I - 420/128 * P + 378/128 * P^2 + ( - 180/128 * P + 35/128 * P^2 ) * P^2 )
     729         4714 :          CALL dbcsr_multiply('N', 'N', 1.0_dp, P, P, 0.0_dp, P2) ! P^2
     730         4714 :          IF (eps_irac_filter_matrix > 0.0_dp) THEN
     731            8 :             occ_in = dbcsr_get_occupation(p2)
     732            8 :             CALL dbcsr_filter(p2, eps_irac_filter_matrix)
     733            8 :             occ_out = dbcsr_get_occupation(p2)
     734              :          END IF
     735         4714 :          r = -180.0_dp/128.0_dp
     736         4714 :          CALL dbcsr_add(T, P, alpha_scalar=0.0_dp, beta_scalar=r) ! T=-180/128*P
     737         4714 :          r = 35.0_dp/128.0_dp
     738         4714 :          CALL dbcsr_add(T, P2, alpha_scalar=1.0_dp, beta_scalar=r) ! T=T+35/128*P^2
     739         4714 :          CALL dbcsr_multiply('N', 'N', 1.0_dp, T, P2, 0.0_dp, FY) ! Y=T*P^2
     740         4714 :          IF (eps_irac_filter_matrix > 0.0_dp) THEN
     741            8 :             occ_in = dbcsr_get_occupation(fy)
     742            8 :             CALL dbcsr_filter(fy, eps_irac_filter_matrix)
     743            8 :             occ_out = dbcsr_get_occupation(fy)
     744              :          END IF
     745         4714 :          r = 378.0_dp/128.0_dp
     746         4714 :          CALL dbcsr_add(FY, P2, alpha_scalar=1.0_dp, beta_scalar=r) ! Y=Y+378/128*P^2
     747         4714 :          r = -420.0_dp/128.0_dp
     748         4714 :          CALL dbcsr_add(FY, P, alpha_scalar=1.0_dp, beta_scalar=r) ! Y=Y-420/128*P
     749         4714 :          r = 315.0_dp/128.0_dp
     750         4714 :          CALL dbcsr_add_on_diag(FY, alpha=r) ! Y=Y+315/128*I
     751              :       CASE DEFAULT
     752         4714 :          CPABORT("This irac_order NYI")
     753              :       END SELECT
     754         4714 :       CALL timestop(handle)
     755         4714 :    END SUBROUTINE qs_ot_refine
     756              : 
     757              : ! **************************************************************************************************
     758              : !> \brief ...
     759              : !> \param matrix_hc ...
     760              : !> \param matrix_x ...
     761              : !> \param matrix_sx ...
     762              : !> \param matrix_gx ...
     763              : !> \param qs_ot_env ...
     764              : ! **************************************************************************************************
     765         7064 :    SUBROUTINE qs_ot_get_derivative_ref(matrix_hc, matrix_x, matrix_sx, matrix_gx, &
     766              :                                        qs_ot_env)
     767              :       TYPE(dbcsr_type), POINTER                          :: matrix_hc, matrix_x, matrix_sx, matrix_gx
     768              :       TYPE(qs_ot_type)                                   :: qs_ot_env
     769              : 
     770              :       CHARACTER(len=*), PARAMETER :: routineN = 'qs_ot_get_derivative_ref'
     771              : 
     772              :       INTEGER                                            :: handle, k, n
     773              :       REAL(dp)                                           :: occ_in, occ_out
     774              :       TYPE(dbcsr_type), POINTER                          :: C, CHC, G, HC, HC_work, SC
     775              : 
     776         3532 :       CALL timeset(routineN, handle)
     777              : 
     778         3532 :       CALL dbcsr_get_info(matrix_x, nfullrows_total=n, nfullcols_total=k)
     779              :       !
     780         3532 :       C => matrix_x ! NBsf*NOcc
     781         3532 :       SC => matrix_sx ! NBsf*NOcc need to be up2date
     782         3532 :       HC => matrix_hc ! NBsf*NOcc
     783         3532 :       G => matrix_gx ! NBsf*NOcc
     784         3532 :       CHC => qs_ot_env%buf1_k_k_sym ! buffer
     785              : 
     786         3532 :       IF (qs_ot_env%settings%do_rotation) THEN
     787              :          ! The physical orbitals are C_current=Q*U. Pull dE/dC_current
     788              :          ! back to the unrotated REF basis before projecting it.
     789            8 :          CALL qs_ot_rot_mat_derivative(qs_ot_env)
     790            8 :          HC_work => qs_ot_env%buf1_n_k
     791              :          CALL dbcsr_multiply('N', 'T', 1.0_dp, HC, qs_ot_env%rot_mat_u, &
     792            8 :                              0.0_dp, HC_work)
     793              :       ELSE
     794              :          HC_work => HC
     795              :       END IF
     796              : 
     797              :       ! C'*(H*C)
     798         3532 :       CALL dbcsr_multiply('T', 'N', 1.0_dp, C, HC_work, 0.0_dp, CHC)
     799         3532 :       IF (qs_ot_env%settings%eps_irac_filter_matrix > 0.0_dp) THEN
     800            4 :          occ_in = dbcsr_get_occupation(chc)
     801            4 :          CALL dbcsr_filter(chc, qs_ot_env%settings%eps_irac_filter_matrix)
     802            4 :          occ_out = dbcsr_get_occupation(chc)
     803              :       END IF
     804              :       ! (S*C)*(C'*H*C)
     805         3532 :       CALL dbcsr_multiply('N', 'N', 1.0_dp, SC, CHC, 0.0_dp, G)
     806         3532 :       IF (qs_ot_env%settings%eps_irac_filter_matrix > 0.0_dp) THEN
     807            4 :          occ_in = dbcsr_get_occupation(g)
     808            4 :          CALL dbcsr_filter(g, qs_ot_env%settings%eps_irac_filter_matrix)
     809            4 :          occ_out = dbcsr_get_occupation(g)
     810              :       END IF
     811              :       ! G = 2*(1-S*C*C')*H*C
     812         3532 :       CALL dbcsr_add(G, HC_work, alpha_scalar=-1.0_dp, beta_scalar=1.0_dp)
     813              :       !
     814         3532 :       CALL timestop(handle)
     815         3532 :    END SUBROUTINE qs_ot_get_derivative_ref
     816              : 
     817              : ! **************************************************************************************************
     818              : !> \brief Transpose a square DBCSR matrix while retaining its target distribution.
     819              : !> \param matrix source matrix
     820              : !> \param transposed transposed matrix
     821              : !> \param identity_template square matrix template
     822              : ! **************************************************************************************************
     823         6166 :    SUBROUTINE qs_ot_square_transpose(matrix, transposed, identity_template)
     824              :       TYPE(dbcsr_type)                                   :: matrix, transposed, identity_template
     825              : 
     826              :       TYPE(dbcsr_type)                                   :: identity
     827              : 
     828         6166 :       CALL dbcsr_copy(transposed, matrix, name='square_transposed')
     829         6166 :       CALL dbcsr_copy(identity, identity_template, name='transpose_identity')
     830         6166 :       CALL dbcsr_set(identity, 0.0_dp)
     831         6166 :       CALL dbcsr_add_on_diag(identity, 1.0_dp)
     832         6166 :       CALL dbcsr_multiply('T', 'N', 1.0_dp, matrix, identity, 0.0_dp, transposed)
     833         6166 :       CALL dbcsr_release(identity)
     834              : 
     835         6166 :    END SUBROUTINE qs_ot_square_transpose
     836              : 
     837              : ! **************************************************************************************************
     838              : !> \brief computes p=x*S*x and the matrix functionals related matrices
     839              : !> \param matrix_x ...
     840              : !> \param matrix_sx ...
     841              : !> \param qs_ot_env ...
     842              : ! **************************************************************************************************
     843       333519 :    SUBROUTINE qs_ot_get_p(matrix_x, matrix_sx, qs_ot_env)
     844              : 
     845              :       TYPE(dbcsr_type), POINTER                          :: matrix_x, matrix_sx
     846              :       TYPE(qs_ot_type)                                   :: qs_ot_env
     847              : 
     848              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'qs_ot_get_p'
     849              :       REAL(KIND=dp), PARAMETER                           :: rone = 1.0_dp, rzero = 0.0_dp
     850              : 
     851              :       INTEGER                                            :: handle, k, max_iter, n
     852              :       LOGICAL                                            :: converged
     853              :       REAL(KIND=dp)                                      :: max_ev, min_ev, threshold
     854              : 
     855       111173 :       CALL timeset(routineN, handle)
     856              : 
     857       111173 :       CALL dbcsr_get_info(matrix_x, nfullrows_total=n, nfullcols_total=k)
     858              : 
     859              :       ! get the overlap
     860              :       CALL dbcsr_multiply('T', 'N', rone, matrix_x, matrix_sx, rzero, &
     861       111173 :                           qs_ot_env%matrix_p)
     862              : 
     863              :       ! get an upper bound for the largest eigenvalue
     864              :       ! try using lancos first and fall back to gershgorin norm if it fails
     865       111173 :       max_iter = 30; threshold = 1.0E-03_dp
     866       111173 :       CALL arnoldi_extremal(qs_ot_env%matrix_p, max_ev, min_ev, converged, threshold, max_iter)
     867       111173 :       qs_ot_env%largest_eval_upper_bound = MAX(max_ev, ABS(min_ev))
     868              : 
     869       111173 :       IF (.NOT. converged) qs_ot_env%largest_eval_upper_bound = dbcsr_gershgorin_norm(qs_ot_env%matrix_p)
     870       111173 :       CALL decide_strategy(qs_ot_env)
     871       111173 :       IF (qs_ot_env%do_taylor) THEN
     872        59864 :          CALL qs_ot_p2m_taylor(qs_ot_env)
     873              :       ELSE
     874        51309 :          CALL qs_ot_p2m_diag(qs_ot_env)
     875              :       END IF
     876              : 
     877       111173 :       IF (qs_ot_env%settings%do_rotation) THEN
     878         3142 :          CALL qs_ot_generate_rotation(qs_ot_env)
     879              :       END IF
     880              : 
     881       111173 :       CALL timestop(handle)
     882              : 
     883       111173 :    END SUBROUTINE qs_ot_get_p
     884              : 
     885              : ! **************************************************************************************************
     886              : !> \brief computes the rotation matrix rot_mat_u that is associated to a given
     887              : !>        rot_mat_x using rot_mat_u=exp(rot_mat_x)
     888              : !> \param qs_ot_env a valid qs_ot_env
     889              : !> \par History
     890              : !>      08.2004 created [Joost VandeVondele]
     891              : !>      12.2024 Rewrite to use only real matrices [Ole Schuett]
     892              : ! **************************************************************************************************
     893         3156 :    SUBROUTINE qs_ot_generate_rotation(qs_ot_env)
     894              : 
     895              :       TYPE(qs_ot_type)                                   :: qs_ot_env
     896              : 
     897              :       CHARACTER(len=*), PARAMETER :: routineN = 'qs_ot_generate_rotation'
     898              : 
     899              :       INTEGER                                            :: handle, k
     900         3156 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: exp_evals_im, exp_evals_re
     901              :       TYPE(dbcsr_type)                                   :: buf_1, buf_2
     902              : 
     903         3156 :       CALL timeset(routineN, handle)
     904              : 
     905         3156 :       CALL dbcsr_get_info(qs_ot_env%rot_mat_x, nfullrows_total=k)
     906              : 
     907         3156 :       IF (k /= 0) THEN
     908              :          ! We want to compute: rot_mat_u = exp(i*rot_mat_x)
     909              : 
     910              :          ! Diagonalize: matrix = i*rot_mat_x.
     911              :          ! Note that matrix is imaginary and hermitian because rot_mat_x is real and anti-symmetric.
     912              :          CALL cp_dbcsr_heevd(matrix_im=qs_ot_env%rot_mat_x, &  ! matrix_re omitted because it's zero
     913              :                              eigenvectors_re=qs_ot_env%rot_mat_evec_re, &
     914              :                              eigenvectors_im=qs_ot_env%rot_mat_evec_im, &
     915              :                              eigenvalues=qs_ot_env%rot_mat_evals, &
     916              :                              para_env=qs_ot_env%para_env, &
     917         3104 :                              blacs_env=qs_ot_env%blacs_env)
     918              : 
     919              :          ! Compute: exp_evals = EXP(-i*rot_mat_evals)
     920        12416 :          ALLOCATE (exp_evals_re(k), exp_evals_im(k))
     921        16758 :          exp_evals_re(:) = COS(-qs_ot_env%rot_mat_evals(:))
     922        16758 :          exp_evals_im(:) = SIN(-qs_ot_env%rot_mat_evals(:))
     923              : 
     924              :          ! Compute: rot_mat_u = \sum_ij exp_evals_ij * |rot_mat_evec_i> <rot_mat_evec_j|
     925              :          ! Note that we need only two matrix multiplications because rot_mat_u is real.
     926         3104 :          CALL dbcsr_copy(buf_1, qs_ot_env%rot_mat_evec_re, name="buf_1")
     927         3104 :          CALL dbcsr_scale_by_vector(buf_1, alpha=exp_evals_re, side='right')
     928         3104 :          CALL dbcsr_copy(buf_2, qs_ot_env%rot_mat_evec_im, name="buf_2")
     929         3104 :          CALL dbcsr_scale_by_vector(buf_2, alpha=exp_evals_im, side='right')
     930         3104 :          CALL dbcsr_add(buf_1, buf_2, alpha_scalar=+1.0_dp, beta_scalar=-1.0_dp)
     931         3104 :          CALL dbcsr_multiply('N', 'T', 1.0_dp, buf_1, qs_ot_env%rot_mat_evec_re, 0.0_dp, qs_ot_env%rot_mat_u)
     932              : 
     933         3104 :          CALL dbcsr_copy(buf_1, qs_ot_env%rot_mat_evec_im)
     934         3104 :          CALL dbcsr_scale_by_vector(buf_1, alpha=exp_evals_re, side='right')
     935         3104 :          CALL dbcsr_copy(buf_2, qs_ot_env%rot_mat_evec_re)
     936         3104 :          CALL dbcsr_scale_by_vector(buf_2, alpha=exp_evals_im, side='right')
     937         3104 :          CALL dbcsr_add(buf_1, buf_2, alpha_scalar=+1.0_dp, beta_scalar=+1.0_dp)
     938         3104 :          CALL dbcsr_multiply('N', 'T', 1.0_dp, buf_1, qs_ot_env%rot_mat_evec_im, 1.0_dp, qs_ot_env%rot_mat_u)
     939              : 
     940              :          ! Clean up.
     941         3104 :          CALL dbcsr_release(buf_1)
     942         3104 :          CALL dbcsr_release(buf_2)
     943         3104 :          DEALLOCATE (exp_evals_re, exp_evals_im)
     944              :       END IF
     945              : 
     946         3156 :       CALL timestop(handle)
     947              : 
     948         6312 :    END SUBROUTINE qs_ot_generate_rotation
     949              : 
     950              : ! **************************************************************************************************
     951              : !> \brief computes the derivative fields with respect to rot_mat_x
     952              : !> \param qs_ot_env valid qs_ot_env. In particular qs_ot_generate_rotation has to be called before
     953              : !>                        and the rot_mat_dedu matrix has to be up to date
     954              : !> \par History
     955              : !>      08.2004 created [ Joost VandeVondele ]
     956              : !>      12.2024 Rewrite to use only real matrices [Ole Schuett]
     957              : ! **************************************************************************************************
     958         1596 :    SUBROUTINE qs_ot_rot_mat_derivative(qs_ot_env)
     959              :       TYPE(qs_ot_type)                         :: qs_ot_env
     960              : 
     961              :       CHARACTER(len=*), PARAMETER :: routineN = 'qs_ot_rot_mat_derivative'
     962              : 
     963              :       INTEGER                                  :: col, handle, i, iblock, j, k, max_blocks, nblocks, row
     964         1596 :       INTEGER, ALLOCATABLE, DIMENSION(:)       :: cols, rows
     965         1596 :       INTEGER, DIMENSION(:), POINTER           :: col_blk_offset, col_blk_size, row_blk_offset, row_blk_size
     966              :       REAL(KIND=dp)                            :: e1, e2
     967              :       TYPE(dbcsr_type)                         :: outer_deriv_re, outer_deriv_im, mat_buf, &
     968              :                                                   inner_deriv_re, inner_deriv_im
     969              :       TYPE(dbcsr_distribution_type)            :: dist
     970              :       TYPE(dbcsr_iterator_type)                :: iter
     971         1596 :       REAL(dp), DIMENSION(:, :), POINTER       :: block_in_re, block_in_im, block_out_re, block_out_im
     972              :       LOGICAL                                  :: duplicate, found_in_im, found_in_re, found_out_im, &
     973              :                                                   found_out_re
     974              :       REAL(KIND=dp)                            :: im_part, re_part
     975              :       COMPLEX(dp)                              :: cval_in, cval_out
     976         1596 :       CALL timeset(routineN, handle)
     977              : 
     978         1596 :       CALL dbcsr_get_info(qs_ot_env%rot_mat_u, nfullrows_total=k)
     979         1596 :       IF (k /= 0) THEN
     980         1570 :          CALL dbcsr_copy(qs_ot_env%matrix_buf1, qs_ot_env%rot_mat_dedu)
     981              :          ! now we get to the derivative wrt the antisymmetric matrix rot_mat_x
     982         1570 :          CALL dbcsr_copy(mat_buf, qs_ot_env%rot_mat_dedu, "mat_buf")
     983              : 
     984              :          ! inner_deriv_ij = <rot_mat_evec_i| rot_mat_dedu |rot_mat_evec_j>
     985         1570 :          CALL dbcsr_copy(inner_deriv_re, qs_ot_env%rot_mat_dedu, "inner_deriv_re") ! TODO just create
     986         1570 :          CALL dbcsr_copy(inner_deriv_im, qs_ot_env%rot_mat_dedu, "inner_deriv_im") ! TODO just create
     987              : 
     988         1570 :          CALL dbcsr_multiply('T', 'N', +1.0_dp, qs_ot_env%rot_mat_dedu, qs_ot_env%rot_mat_evec_im, 0.0_dp, mat_buf)
     989         1570 :          CALL dbcsr_multiply('T', 'N', +1.0_dp, qs_ot_env%rot_mat_evec_im, mat_buf, 0.0_dp, inner_deriv_re)
     990         1570 :          CALL dbcsr_multiply('T', 'N', +1.0_dp, qs_ot_env%rot_mat_evec_re, mat_buf, 0.0_dp, inner_deriv_im)
     991              : 
     992         1570 :          CALL dbcsr_multiply('T', 'N', +1.0_dp, qs_ot_env%rot_mat_dedu, qs_ot_env%rot_mat_evec_re, 0.0_dp, mat_buf)
     993         1570 :          CALL dbcsr_multiply('T', 'N', +1.0_dp, qs_ot_env%rot_mat_evec_re, mat_buf, 1.0_dp, inner_deriv_re)
     994         1570 :          CALL dbcsr_multiply('T', 'N', -1.0_dp, qs_ot_env%rot_mat_evec_im, mat_buf, 1.0_dp, inner_deriv_im)
     995              : 
     996              :          ! Real and imaginary products can have different sparse block patterns.
     997              :          ! Form their union explicitly and treat a missing partner block as zero.
     998         1570 :          max_blocks = 0
     999         1570 :          CALL dbcsr_iterator_start(iter, inner_deriv_re)
    1000         2354 :          DO WHILE (dbcsr_iterator_blocks_left(iter))
    1001          784 :             CALL dbcsr_iterator_next_block(iter, row, col)
    1002          784 :             max_blocks = max_blocks + 1
    1003              :          END DO
    1004         1570 :          CALL dbcsr_iterator_stop(iter)
    1005         1570 :          CALL dbcsr_iterator_start(iter, inner_deriv_im)
    1006         2354 :          DO WHILE (dbcsr_iterator_blocks_left(iter))
    1007          784 :             CALL dbcsr_iterator_next_block(iter, row, col)
    1008          784 :             max_blocks = max_blocks + 1
    1009              :          END DO
    1010         1570 :          CALL dbcsr_iterator_stop(iter)
    1011              : 
    1012         6280 :          ALLOCATE (rows(MAX(max_blocks, 1)), cols(MAX(max_blocks, 1)))
    1013         1570 :          nblocks = 0
    1014         1570 :          CALL dbcsr_iterator_start(iter, inner_deriv_re)
    1015         2354 :          DO WHILE (dbcsr_iterator_blocks_left(iter))
    1016          784 :             CALL dbcsr_iterator_next_block(iter, row, col)
    1017          784 :             duplicate = .FALSE.
    1018          784 :             DO iblock = 1, nblocks
    1019          784 :                duplicate = duplicate .OR. (rows(iblock) == row .AND. cols(iblock) == col)
    1020              :             END DO
    1021         2354 :             IF (.NOT. duplicate) THEN
    1022          784 :                nblocks = nblocks + 1
    1023          784 :                rows(nblocks) = row
    1024          784 :                cols(nblocks) = col
    1025              :             END IF
    1026              :          END DO
    1027         1570 :          CALL dbcsr_iterator_stop(iter)
    1028         1570 :          CALL dbcsr_iterator_start(iter, inner_deriv_im)
    1029         2354 :          DO WHILE (dbcsr_iterator_blocks_left(iter))
    1030          784 :             CALL dbcsr_iterator_next_block(iter, row, col)
    1031          784 :             duplicate = .FALSE.
    1032         1568 :             DO iblock = 1, nblocks
    1033         1568 :                duplicate = duplicate .OR. (rows(iblock) == row .AND. cols(iblock) == col)
    1034              :             END DO
    1035         2354 :             IF (.NOT. duplicate) THEN
    1036            0 :                nblocks = nblocks + 1
    1037            0 :                rows(nblocks) = row
    1038            0 :                cols(nblocks) = col
    1039              :             END IF
    1040              :          END DO
    1041         1570 :          CALL dbcsr_iterator_stop(iter)
    1042              : 
    1043              :          CALL dbcsr_get_info(inner_deriv_re, distribution=dist, row_blk_size=row_blk_size, &
    1044         1570 :                              col_blk_size=col_blk_size)
    1045              :          CALL dbcsr_create(outer_deriv_re, "outer_deriv_re", dist, dbcsr_type_no_symmetry, &
    1046         1570 :                            row_blk_size, col_blk_size)
    1047              :          CALL dbcsr_create(outer_deriv_im, "outer_deriv_im", dist, dbcsr_type_no_symmetry, &
    1048         1570 :                            row_blk_size, col_blk_size)
    1049         1570 :          IF (nblocks > 0) THEN
    1050          784 :             CALL dbcsr_reserve_blocks(outer_deriv_re, rows=rows(1:nblocks), cols=cols(1:nblocks))
    1051          784 :             CALL dbcsr_reserve_blocks(outer_deriv_im, rows=rows(1:nblocks), cols=cols(1:nblocks))
    1052              :          END IF
    1053         1570 :          CALL dbcsr_finalize(outer_deriv_re)
    1054         1570 :          CALL dbcsr_finalize(outer_deriv_im)
    1055         1570 :          CALL dbcsr_set(outer_deriv_re, 0.0_dp)
    1056         1570 :          CALL dbcsr_set(outer_deriv_im, 0.0_dp)
    1057              : 
    1058         1570 :          CALL dbcsr_get_info(outer_deriv_re, row_blk_offset=row_blk_offset, col_blk_offset=col_blk_offset)
    1059         1570 :          CALL dbcsr_iterator_start(iter, outer_deriv_re)
    1060         2354 :          DO WHILE (dbcsr_iterator_blocks_left(iter))
    1061          784 :             CALL dbcsr_iterator_next_block(iter, row, col)
    1062          784 :             CALL dbcsr_get_block_p(inner_deriv_re, row, col, block_in_re, found_in_re)
    1063          784 :             CALL dbcsr_get_block_p(inner_deriv_im, row, col, block_in_im, found_in_im)
    1064          784 :             CALL dbcsr_get_block_p(outer_deriv_re, row, col, block_out_re, found_out_re)
    1065          784 :             CALL dbcsr_get_block_p(outer_deriv_im, row, col, block_out_im, found_out_im)
    1066          784 :             CPASSERT(found_out_re .AND. found_out_im)
    1067              : 
    1068         5943 :             DO i = 1, SIZE(block_out_re, 1)
    1069        25726 :             DO j = 1, SIZE(block_out_re, 2)
    1070        21353 :                e1 = qs_ot_env%rot_mat_evals(row_blk_offset(row) + i - 1)
    1071        21353 :                e2 = qs_ot_env%rot_mat_evals(col_blk_offset(col) + j - 1)
    1072        21353 :                re_part = 0.0_dp
    1073        21353 :                im_part = 0.0_dp
    1074        21353 :                IF (found_in_re) re_part = block_in_re(i, j)
    1075        21353 :                IF (found_in_im) im_part = block_in_im(i, j)
    1076        21353 :                cval_in = CMPLX(re_part, im_part, dp)
    1077        21353 :                cval_out = cval_in*cint(e1, e2)
    1078        21353 :                block_out_re(i, j) = REAL(cval_out)
    1079        24942 :                block_out_im(i, j) = AIMAG(cval_out)
    1080              :             END DO
    1081              :             END DO
    1082              :          END DO
    1083         1570 :          CALL dbcsr_iterator_stop(iter)
    1084         1570 :          DEALLOCATE (rows, cols)
    1085         1570 :          CALL dbcsr_release(inner_deriv_re)
    1086         1570 :          CALL dbcsr_release(inner_deriv_im)
    1087              : 
    1088              :          ! Compute: matrix_buf1 = \sum_i outer_deriv_ij * |rot_mat_evec_i> <rot_mat_evec_j|
    1089         1570 :          CALL dbcsr_multiply('N', 'N', +1.0_dp, qs_ot_env%rot_mat_evec_re, outer_deriv_re, 0.0_dp, mat_buf)
    1090         1570 :          CALL dbcsr_multiply('N', 'N', -1.0_dp, qs_ot_env%rot_mat_evec_im, outer_deriv_im, 1.0_dp, mat_buf)
    1091         1570 :          CALL dbcsr_multiply('N', 'T', +1.0_dp, mat_buf, qs_ot_env%rot_mat_evec_re, 0.0_dp, qs_ot_env%matrix_buf1)
    1092              : 
    1093         1570 :          CALL dbcsr_multiply('N', 'N', +1.0_dp, qs_ot_env%rot_mat_evec_re, outer_deriv_im, 0.0_dp, mat_buf)
    1094         1570 :          CALL dbcsr_multiply('N', 'N', +1.0_dp, qs_ot_env%rot_mat_evec_im, outer_deriv_re, 1.0_dp, mat_buf)
    1095         1570 :          CALL dbcsr_multiply('N', 'T', +1.0_dp, mat_buf, qs_ot_env%rot_mat_evec_im, 1.0_dp, qs_ot_env%matrix_buf1)
    1096              : 
    1097              :          ! Account for anti-symmetry of rot_mat_x without relying on
    1098              :          ! STRICT-only matrix buffers. REF uses the same finite chart.
    1099         1570 :          CALL qs_ot_square_transpose(qs_ot_env%matrix_buf1, mat_buf, qs_ot_env%rot_mat_u)
    1100         1570 :          CALL dbcsr_copy(qs_ot_env%rot_mat_gx, mat_buf)
    1101              :          CALL dbcsr_add(qs_ot_env%rot_mat_gx, qs_ot_env%matrix_buf1, &
    1102         1570 :                         alpha_scalar=1.0_dp, beta_scalar=-1.0_dp)
    1103              : 
    1104         1570 :          CALL dbcsr_release(mat_buf)
    1105         1570 :          CALL dbcsr_release(outer_deriv_re)
    1106        10990 :          CALL dbcsr_release(outer_deriv_im)
    1107              :       END IF
    1108         3192 :       CALL timestop(handle)
    1109              :    CONTAINS
    1110              : 
    1111              : ! **************************************************************************************************
    1112              : !> \brief ...
    1113              : !> \param e1 ...
    1114              : !> \param e2 ...
    1115              : !> \return ...
    1116              : ! **************************************************************************************************
    1117        21353 :       FUNCTION cint(e1, e2)
    1118              :       REAL(KIND=dp)                                      :: e1, e2
    1119              :       COMPLEX(KIND=dp)                                   :: cint
    1120              : 
    1121              :       COMPLEX(KIND=dp)                                   :: l1, l2, x
    1122              :       INTEGER                                            :: I
    1123              : 
    1124        21353 :          l1 = (0.0_dp, -1.0_dp)*e1
    1125        21353 :          l2 = (0.0_dp, -1.0_dp)*e2
    1126        21353 :          IF (ABS(l1 - l2) > 0.5_dp) THEN
    1127         1424 :             cint = (EXP(l1) - EXP(l2))/(l1 - l2)
    1128              :          ELSE
    1129              :             x = 1.0_dp
    1130              :             cint = 0.0_dp
    1131       338793 :             DO I = 1, 16
    1132       318864 :                cint = cint + x
    1133       338793 :                x = x*(l1 - l2)/REAL(I + 1, KIND=dp)
    1134              :             END DO
    1135        19929 :             cint = cint*EXP(l2)
    1136              :          END IF
    1137        21353 :       END FUNCTION cint
    1138              :    END SUBROUTINE qs_ot_rot_mat_derivative
    1139              : 
    1140              : ! **************************************************************************************************
    1141              : !> \brief decide strategy
    1142              : !>        tries to decide if the taylor expansion of cos(sqrt(xsx)) converges rapidly enough
    1143              : !>        to make a taylor expansion of the functions cos(sqrt(xsx)) and sin(sqrt(xsx))/sqrt(xsx)
    1144              : !>        and their derivatives faster than their computation based on diagonalization since xsx can
    1145              : !>        be very small, especially during dynamics, only a few terms might indeed be needed we find
    1146              : !>        the necessary order N to have largest_eval_upper_bound**(N+1)/(2(N+1))! < eps_taylor
    1147              : !> \param qs_ot_env ...
    1148              : ! **************************************************************************************************
    1149       111173 :    SUBROUTINE decide_strategy(qs_ot_env)
    1150              :       TYPE(qs_ot_type)                                   :: qs_ot_env
    1151              : 
    1152              :       INTEGER                                            :: N
    1153              :       REAL(KIND=dp)                                      :: num_error
    1154              : 
    1155       111173 :       qs_ot_env%do_taylor = .FALSE.
    1156       111173 :       N = 0
    1157       111173 :       num_error = qs_ot_env%largest_eval_upper_bound/(2.0_dp)
    1158       472429 :       DO WHILE (num_error > qs_ot_env%settings%eps_taylor .AND. N <= qs_ot_env%settings%max_taylor)
    1159       361256 :          N = N + 1
    1160       407279 :          num_error = num_error*qs_ot_env%largest_eval_upper_bound/REAL((2*N + 1)*(2*N + 2), KIND=dp)
    1161              :       END DO
    1162              :       ! An O(P) matrix-function term can be below eps_taylor while its O(X)
    1163              :       ! orbital derivative is still needed near P=X^T*S*X=0.
    1164       111173 :       qs_ot_env%taylor_order = MAX(1, N)
    1165       111173 :       IF (qs_ot_env%taylor_order <= qs_ot_env%settings%max_taylor) THEN
    1166        59864 :          qs_ot_env%do_taylor = .TRUE.
    1167              :       END IF
    1168              : 
    1169       111173 :    END SUBROUTINE decide_strategy
    1170              : 
    1171              : ! **************************************************************************************************
    1172              : !> \brief c=(c0*cos(p^0.5)+x*sin(p^0.5)*p^(-0.5)) x rot_mat_u
    1173              : !>        this assumes that x is already ortho to S*C0, and that p is x*S*x
    1174              : !>        rot_mat_u is an optional rotation matrix
    1175              : !> \param matrix_c ...
    1176              : !> \param matrix_x ...
    1177              : !> \param qs_ot_env ...
    1178              : ! **************************************************************************************************
    1179       206450 :    SUBROUTINE qs_ot_get_orbitals(matrix_c, matrix_x, qs_ot_env)
    1180              : 
    1181              :       TYPE(dbcsr_type), POINTER                          :: matrix_c, matrix_x
    1182              :       TYPE(qs_ot_type)                                   :: qs_ot_env
    1183              : 
    1184              :       CHARACTER(len=*), PARAMETER :: routineN = 'qs_ot_get_orbitals'
    1185              :       REAL(KIND=dp), PARAMETER                           :: rone = 1.0_dp, rzero = 0.0_dp
    1186              : 
    1187              :       INTEGER                                            :: handle, k, n
    1188              :       TYPE(dbcsr_type), POINTER                          :: matrix_kk
    1189              : 
    1190       103225 :       CALL timeset(routineN, handle)
    1191              : 
    1192       103225 :       CALL dbcsr_get_info(matrix_x, nfullrows_total=n, nfullcols_total=k)
    1193              : 
    1194              :       ! rotate the multiplying matrices cosp and sinp instead of the result,
    1195              :       ! this should be cheaper for large basis sets
    1196       103225 :       IF (qs_ot_env%settings%do_rotation) THEN
    1197         2938 :          matrix_kk => qs_ot_env%matrix_buf1
    1198              :          CALL dbcsr_multiply('N', 'N', rone, qs_ot_env%matrix_cosp, &
    1199         2938 :                              qs_ot_env%rot_mat_u, rzero, matrix_kk)
    1200              :       ELSE
    1201       100287 :          matrix_kk => qs_ot_env%matrix_cosp
    1202              :       END IF
    1203              : 
    1204              :       CALL dbcsr_multiply('N', 'N', rone, qs_ot_env%matrix_c0, matrix_kk, &
    1205       103225 :                           rzero, matrix_c)
    1206              : 
    1207       103225 :       IF (qs_ot_env%settings%do_rotation) THEN
    1208         2938 :          matrix_kk => qs_ot_env%matrix_buf1
    1209              :          CALL dbcsr_multiply('N', 'N', rone, qs_ot_env%matrix_sinp, &
    1210         2938 :                              qs_ot_env%rot_mat_u, rzero, matrix_kk)
    1211              :       ELSE
    1212       100287 :          matrix_kk => qs_ot_env%matrix_sinp
    1213              :       END IF
    1214              :       CALL dbcsr_multiply('N', 'N', rone, matrix_x, matrix_kk, &
    1215       103225 :                           rone, matrix_c)
    1216              : 
    1217       103225 :       CALL timestop(handle)
    1218              : 
    1219       103225 :    END SUBROUTINE qs_ot_get_orbitals
    1220              : 
    1221              : ! **************************************************************************************************
    1222              : !> \brief this routines computes dE/dx=dx, with dx ortho to sc0
    1223              : !>        needs dE/dC=hc,C0,X,SX,p
    1224              : !>        if preconditioned it will not be the derivative, but the lagrangian multiplier
    1225              : !>        is changed so that P*dE/dx is the right derivative (i.e. in the allowed subspace)
    1226              : !> \param matrix_hc ...
    1227              : !> \param matrix_x ...
    1228              : !> \param matrix_sx ...
    1229              : !> \param matrix_gx ...
    1230              : !> \param qs_ot_env ...
    1231              : ! **************************************************************************************************
    1232        79753 :    SUBROUTINE qs_ot_get_derivative(matrix_hc, matrix_x, matrix_sx, matrix_gx, &
    1233              :                                    qs_ot_env)
    1234              :       TYPE(dbcsr_type), POINTER                          :: matrix_hc, matrix_x, matrix_sx, matrix_gx
    1235              :       TYPE(qs_ot_type)                                   :: qs_ot_env
    1236              : 
    1237              :       CHARACTER(len=*), PARAMETER :: routineN = 'qs_ot_get_derivative'
    1238              :       REAL(KIND=dp), PARAMETER                           :: rone = 1.0_dp, rzero = 0.0_dp
    1239              : 
    1240              :       INTEGER                                            :: handle
    1241              :       TYPE(dbcsr_type), POINTER                          :: matrix_hc_local
    1242              : 
    1243        79753 :       CALL timeset(routineN, handle)
    1244              : 
    1245        79753 :       NULLIFY (matrix_hc_local)
    1246              : 
    1247              :       ! could in principle be taken inside qs_ot_get_derivative_* for increased efficiency
    1248              :       ! create a local rotated version of matrix_hc leaving matrix_hc untouched (needed
    1249              :       ! for lagrangian multipliers)
    1250        79753 :       IF (qs_ot_env%settings%do_rotation) THEN
    1251         1588 :          CALL dbcsr_copy(matrix_gx, matrix_hc) ! use gx as temporary
    1252         1588 :          CALL dbcsr_init_p(matrix_hc_local)
    1253         1588 :          CALL dbcsr_copy(matrix_hc_local, matrix_hc, name='matrix_hc_local')
    1254         1588 :          CALL dbcsr_set(matrix_hc_local, 0.0_dp)
    1255         1588 :          CALL dbcsr_multiply('N', 'T', rone, matrix_gx, qs_ot_env%rot_mat_u, rzero, matrix_hc_local)
    1256              :       ELSE
    1257        78165 :          matrix_hc_local => matrix_hc
    1258              :       END IF
    1259              : 
    1260        79753 :       IF (qs_ot_env%do_taylor) THEN
    1261        44113 :          CALL qs_ot_get_derivative_taylor(matrix_hc_local, matrix_x, matrix_sx, matrix_gx, qs_ot_env)
    1262              :       ELSE
    1263        35640 :          CALL qs_ot_get_derivative_diag(matrix_hc_local, matrix_x, matrix_sx, matrix_gx, qs_ot_env)
    1264              :       END IF
    1265              : 
    1266        79753 :       CALL qs_ot_project_gradient(qs_ot_env, matrix_gx)
    1267              :       ! also treat the rot_mat gradient here
    1268        79753 :       IF (qs_ot_env%settings%do_rotation) THEN
    1269         1588 :          CALL qs_ot_rot_mat_derivative(qs_ot_env)
    1270              :       END IF
    1271              : 
    1272        79753 :       IF (qs_ot_env%settings%do_rotation) THEN
    1273         1588 :          CALL dbcsr_release_p(matrix_hc_local)
    1274              :       END IF
    1275              : 
    1276        79753 :       CALL timestop(handle)
    1277              : 
    1278        79753 :    END SUBROUTINE qs_ot_get_derivative
    1279              : 
    1280              : ! **************************************************************************************************
    1281              : !> \brief Project a real STRICT gradient, or an identity-metric fallback direction.
    1282              : !> \param qs_ot_env OT channel state
    1283              : !> \param matrix_gx real component to project in place
    1284              : !> \param use_preconditioner use the attached preconditioner, default true
    1285              : ! **************************************************************************************************
    1286        79753 :    SUBROUTINE qs_ot_project_gradient(qs_ot_env, matrix_gx, use_preconditioner)
    1287              :       TYPE(qs_ot_type)                                   :: qs_ot_env
    1288              :       TYPE(dbcsr_type), POINTER                          :: matrix_gx
    1289              :       LOGICAL, INTENT(IN), OPTIONAL                      :: use_preconditioner
    1290              : 
    1291              :       REAL(KIND=dp), PARAMETER                           :: rone = 1.0_dp, rzero = 0.0_dp
    1292              : 
    1293              :       LOGICAL                                            :: preconditioned
    1294              :       TYPE(dbcsr_type), POINTER                          :: target_re
    1295              : 
    1296        79753 :       preconditioned = .TRUE.
    1297        79753 :       IF (PRESENT(use_preconditioner)) preconditioned = use_preconditioner
    1298            0 :       IF (.NOT. preconditioned) qs_ot_env%os_valid = .FALSE.
    1299        79753 :       IF (preconditioned .AND. ASSOCIATED(qs_ot_env%preconditioner)) THEN
    1300        69255 :          target_re => qs_ot_env%matrix_psc0
    1301              :       ELSE
    1302        10498 :          target_re => qs_ot_env%matrix_sc0
    1303              :       END IF
    1304              :       ! first make the matrix os if not yet valid
    1305        79753 :       IF (.NOT. qs_ot_env%os_valid) THEN
    1306              :          ! this assumes that the preconditioner is a single matrix
    1307              :          ! that maps sc0 onto psc0
    1308              : 
    1309         8630 :          IF (preconditioned .AND. ASSOCIATED(qs_ot_env%preconditioner)) THEN
    1310              :             CALL apply_preconditioner(qs_ot_env%preconditioner, qs_ot_env%matrix_sc0, &
    1311         7632 :                                       qs_ot_env%matrix_psc0)
    1312              :          END IF
    1313              :          CALL dbcsr_multiply('T', 'N', rone, &
    1314              :                              qs_ot_env%matrix_sc0, target_re, &
    1315         8630 :                              rzero, qs_ot_env%matrix_os)
    1316              :          CALL cp_dbcsr_cholesky_decompose(qs_ot_env%matrix_os, &
    1317         8630 :                                           para_env=qs_ot_env%para_env, blacs_env=qs_ot_env%blacs_env)
    1318              :          CALL cp_dbcsr_cholesky_invert(qs_ot_env%matrix_os, &
    1319              :                                        para_env=qs_ot_env%para_env, blacs_env=qs_ot_env%blacs_env, &
    1320         8630 :                                        uplo_to_full=.TRUE.)
    1321         8630 :          qs_ot_env%os_valid = preconditioned
    1322              :       END IF
    1323              :       CALL dbcsr_multiply('T', 'N', rone, target_re, matrix_gx, &
    1324        79753 :                           rzero, qs_ot_env%matrix_buf1_ortho)
    1325              :       CALL dbcsr_multiply('N', 'N', rone, qs_ot_env%matrix_os, &
    1326        79753 :                           qs_ot_env%matrix_buf1_ortho, rzero, qs_ot_env%matrix_buf2_ortho)
    1327              :       CALL dbcsr_multiply('N', 'N', -rone, qs_ot_env%matrix_sc0, &
    1328        79753 :                           qs_ot_env%matrix_buf2_ortho, rone, matrix_gx)
    1329              : 
    1330        79753 :    END SUBROUTINE qs_ot_project_gradient
    1331              : 
    1332              : ! **************************************************************************************************
    1333              : !> \brief ...
    1334              : !> \param matrix_hc ...
    1335              : !> \param matrix_x ...
    1336              : !> \param matrix_sx ...
    1337              : !> \param matrix_gx ...
    1338              : !> \param qs_ot_env ...
    1339              : ! **************************************************************************************************
    1340       106920 :    SUBROUTINE qs_ot_get_derivative_diag(matrix_hc, matrix_x, matrix_sx, matrix_gx, &
    1341              :                                         qs_ot_env)
    1342              : 
    1343              :       TYPE(dbcsr_type), POINTER                          :: matrix_hc, matrix_x, matrix_sx, matrix_gx
    1344              :       TYPE(qs_ot_type)                                   :: qs_ot_env
    1345              : 
    1346              :       CHARACTER(len=*), PARAMETER :: routineN = 'qs_ot_get_derivative_diag'
    1347              :       REAL(KIND=dp), PARAMETER                           :: rone = 1.0_dp, rzero = 0.0_dp
    1348              : 
    1349              :       INTEGER                                            :: handle, k, n
    1350              :       TYPE(dbcsr_distribution_type)                      :: dist
    1351              : 
    1352        35640 :       CALL timeset(routineN, handle)
    1353              : 
    1354        35640 :       CALL dbcsr_get_info(matrix_x, nfullrows_total=n, nfullcols_total=k)
    1355              : 
    1356              :       ! go for the derivative now
    1357              :       ! this de/dc*(dX/dx)*sinp
    1358        35640 :       CALL dbcsr_multiply('N', 'N', rone, matrix_hc, qs_ot_env%matrix_sinp, rzero, matrix_gx)
    1359              :       ! overlap hc*x
    1360        35640 :       CALL dbcsr_multiply('T', 'N', rone, matrix_hc, matrix_x, rzero, qs_ot_env%matrix_buf2)
    1361              :       ! get it in the basis of the eigenvectors
    1362              :       CALL dbcsr_multiply('N', 'N', rone, qs_ot_env%matrix_buf2, qs_ot_env%matrix_r, &
    1363        35640 :                           rzero, qs_ot_env%matrix_buf1)
    1364              :       CALL dbcsr_multiply('T', 'N', rone, qs_ot_env%matrix_r, qs_ot_env%matrix_buf1, &
    1365        35640 :                           rzero, qs_ot_env%matrix_buf2)
    1366              : 
    1367              :       ! get the schur product of O_uv*B_uv
    1368              :       CALL dbcsr_hadamard_product(qs_ot_env%matrix_buf2, qs_ot_env%matrix_sinp_b, &
    1369        35640 :                                   qs_ot_env%matrix_buf3)
    1370              : 
    1371              :       ! overlap hc*c0
    1372              :       CALL dbcsr_multiply('T', 'N', rone, matrix_hc, qs_ot_env%matrix_c0, rzero, &
    1373        35640 :                           qs_ot_env%matrix_buf2)
    1374              :       ! get it in the basis of the eigenvectors
    1375              :       CALL dbcsr_multiply('N', 'N', rone, qs_ot_env%matrix_buf2, qs_ot_env%matrix_r, &
    1376        35640 :                           rzero, qs_ot_env%matrix_buf1)
    1377              :       CALL dbcsr_multiply('T', 'N', rone, qs_ot_env%matrix_r, qs_ot_env%matrix_buf1, &
    1378        35640 :                           rzero, qs_ot_env%matrix_buf2)
    1379              : 
    1380              :       CALL dbcsr_hadamard_product(qs_ot_env%matrix_buf2, qs_ot_env%matrix_cosp_b, &
    1381        35640 :                                   qs_ot_env%matrix_buf4)
    1382              : 
    1383              :       ! add the two bs and compute b+b^T
    1384              :       CALL dbcsr_add(qs_ot_env%matrix_buf3, qs_ot_env%matrix_buf4, &
    1385        35640 :                      alpha_scalar=rone, beta_scalar=rone)
    1386              : 
    1387              :       ! get the b in the eigenvector basis
    1388              :       CALL dbcsr_multiply('N', 'T', rone, qs_ot_env%matrix_buf3, qs_ot_env%matrix_r, &
    1389        35640 :                           rzero, qs_ot_env%matrix_buf1)
    1390              :       CALL dbcsr_multiply('N', 'N', rone, qs_ot_env%matrix_r, qs_ot_env%matrix_buf1, &
    1391        35640 :                           rzero, qs_ot_env%matrix_buf3)
    1392        35640 :       CALL dbcsr_get_info(qs_ot_env%matrix_buf3, distribution=dist)
    1393              :       CALL dbcsr_transposed(qs_ot_env%matrix_buf1, qs_ot_env%matrix_buf3, &
    1394              :                             shallow_data_copy=.FALSE., use_distribution=dist, &
    1395        35640 :                             transpose_distribution=.FALSE.)
    1396              :       CALL dbcsr_add(qs_ot_env%matrix_buf3, qs_ot_env%matrix_buf1, &
    1397        35640 :                      alpha_scalar=rone, beta_scalar=rone)
    1398              : 
    1399              :       ! and add to the derivative
    1400              :       CALL dbcsr_multiply('N', 'N', rone, matrix_sx, qs_ot_env%matrix_buf3, &
    1401        35640 :                           rone, matrix_gx)
    1402        35640 :       CALL timestop(handle)
    1403              : 
    1404        35640 :    END SUBROUTINE qs_ot_get_derivative_diag
    1405              : 
    1406              : ! **************************************************************************************************
    1407              : !> \brief compute the derivative of the taylor expansion below
    1408              : !> \param matrix_hc ...
    1409              : !> \param matrix_x ...
    1410              : !> \param matrix_sx ...
    1411              : !> \param matrix_gx ...
    1412              : !> \param qs_ot_env ...
    1413              : ! **************************************************************************************************
    1414       176452 :    SUBROUTINE qs_ot_get_derivative_taylor(matrix_hc, matrix_x, matrix_sx, matrix_gx, &
    1415              :                                           qs_ot_env)
    1416              : 
    1417              :       TYPE(dbcsr_type), POINTER                          :: matrix_hc, matrix_x, matrix_sx, matrix_gx
    1418              :       TYPE(qs_ot_type)                                   :: qs_ot_env
    1419              : 
    1420              :       CHARACTER(len=*), PARAMETER :: routineN = 'qs_ot_get_derivative_taylor'
    1421              :       REAL(KIND=dp), PARAMETER                           :: rone = 1.0_dp, rzero = 0.0_dp
    1422              : 
    1423              :       INTEGER                                            :: handle, i, k, n
    1424              :       REAL(KIND=dp)                                      :: cosfactor, sinfactor
    1425              :       TYPE(dbcsr_distribution_type)                      :: dist
    1426              :       TYPE(dbcsr_type), POINTER                          :: matrix_left, matrix_right
    1427              : 
    1428        44113 :       CALL timeset(routineN, handle)
    1429              : 
    1430        44113 :       CALL dbcsr_get_info(matrix_x, nfullrows_total=n, nfullcols_total=k)
    1431              : 
    1432              :       ! go for the derivative now
    1433              :       ! this de/dc*(dX/dx)*sinp i.e. zeroth order
    1434        44113 :       CALL dbcsr_multiply('N', 'N', rone, matrix_hc, qs_ot_env%matrix_sinp, rzero, matrix_gx)
    1435              : 
    1436        44113 :       IF (qs_ot_env%taylor_order <= 0) THEN
    1437            0 :          CALL timestop(handle)
    1438            0 :          RETURN
    1439              :       END IF
    1440              : 
    1441              :       ! we store the matrix that will multiply sx in matrix_r
    1442        44113 :       CALL dbcsr_set(qs_ot_env%matrix_r, rzero)
    1443              : 
    1444              :       ! just better names for matrix_cosp_b and matrix_sinp_b (they are buffer space here)
    1445        44113 :       matrix_left => qs_ot_env%matrix_cosp_b
    1446        44113 :       matrix_right => qs_ot_env%matrix_sinp_b
    1447              : 
    1448              :       ! overlap hc*x and add its transpose to matrix_left
    1449        44113 :       CALL dbcsr_multiply('T', 'N', rone, matrix_hc, matrix_x, rzero, matrix_left)
    1450        44113 :       CALL dbcsr_get_info(matrix_left, distribution=dist)
    1451              :       CALL dbcsr_transposed(qs_ot_env%matrix_buf1, matrix_left, &
    1452              :                             shallow_data_copy=.FALSE., use_distribution=dist, &
    1453        44113 :                             transpose_distribution=.FALSE.)
    1454              :       CALL dbcsr_add(matrix_left, qs_ot_env%matrix_buf1, &
    1455        44113 :                      alpha_scalar=1.0_dp, beta_scalar=1.0_dp)
    1456        44113 :       CALL dbcsr_copy(matrix_right, matrix_left)
    1457              : 
    1458              :       ! first order
    1459        44113 :       sinfactor = -1.0_dp/(2.0_dp*3.0_dp)
    1460              :       CALL dbcsr_add(qs_ot_env%matrix_r, matrix_left, &
    1461        44113 :                      alpha_scalar=1.0_dp, beta_scalar=sinfactor)
    1462              : 
    1463              :       !      M
    1464              :       !    OM+MO
    1465              :       ! OOM+OMO+MOO
    1466              :       !   ...
    1467        82991 :       DO i = 2, qs_ot_env%taylor_order
    1468        38878 :          sinfactor = sinfactor*(-1.0_dp)/REAL(2*i*(2*i + 1), KIND=dp)
    1469        38878 :          CALL dbcsr_multiply('N', 'N', rone, qs_ot_env%matrix_p, matrix_left, rzero, qs_ot_env%matrix_buf1)
    1470        38878 :          CALL dbcsr_multiply('N', 'N', rone, matrix_right, qs_ot_env%matrix_p, rzero, matrix_left)
    1471        38878 :          CALL dbcsr_copy(matrix_right, matrix_left)
    1472              :          CALL dbcsr_add(matrix_left, qs_ot_env%matrix_buf1, &
    1473        38878 :                         1.0_dp, 1.0_dp)
    1474              :          CALL dbcsr_add(qs_ot_env%matrix_r, matrix_left, &
    1475        82991 :                         alpha_scalar=1.0_dp, beta_scalar=sinfactor)
    1476              :       END DO
    1477              : 
    1478              :       ! overlap hc*c0 and add its transpose to matrix_left
    1479        44113 :       CALL dbcsr_multiply('T', 'N', rone, matrix_hc, qs_ot_env%matrix_c0, rzero, matrix_left)
    1480        44113 :       CALL dbcsr_get_info(matrix_left, distribution=dist)
    1481              :       CALL dbcsr_transposed(qs_ot_env%matrix_buf1, matrix_left, &
    1482              :                             shallow_data_copy=.FALSE., use_distribution=dist, &
    1483        44113 :                             transpose_distribution=.FALSE.)
    1484        44113 :       CALL dbcsr_add(matrix_left, qs_ot_env%matrix_buf1, 1.0_dp, 1.0_dp)
    1485        44113 :       CALL dbcsr_copy(matrix_right, matrix_left)
    1486              : 
    1487              :       ! first order
    1488        44113 :       cosfactor = -1.0_dp/(1.0_dp*2.0_dp)
    1489              :       CALL dbcsr_add(qs_ot_env%matrix_r, matrix_left, &
    1490        44113 :                      alpha_scalar=1.0_dp, beta_scalar=cosfactor)
    1491              : 
    1492              :       !      M
    1493              :       !    OM+MO
    1494              :       ! OOM+OMO+MOO
    1495              :       !   ...
    1496        82991 :       DO i = 2, qs_ot_env%taylor_order
    1497        38878 :          cosfactor = cosfactor*(-1.0_dp)/REAL(2*i*(2*i - 1), KIND=dp)
    1498        38878 :          CALL dbcsr_multiply('N', 'N', rone, qs_ot_env%matrix_p, matrix_left, rzero, qs_ot_env%matrix_buf1)
    1499        38878 :          CALL dbcsr_multiply('N', 'N', rone, matrix_right, qs_ot_env%matrix_p, rzero, matrix_left)
    1500        38878 :          CALL dbcsr_copy(matrix_right, matrix_left)
    1501        38878 :          CALL dbcsr_add(matrix_left, qs_ot_env%matrix_buf1, 1.0_dp, 1.0_dp)
    1502              :          CALL dbcsr_add(qs_ot_env%matrix_r, matrix_left, &
    1503        82991 :                         alpha_scalar=1.0_dp, beta_scalar=cosfactor)
    1504              :       END DO
    1505              : 
    1506              :       ! and add to the derivative
    1507        44113 :       CALL dbcsr_multiply('N', 'N', rone, matrix_sx, qs_ot_env%matrix_r, rone, matrix_gx)
    1508              : 
    1509        44113 :       CALL timestop(handle)
    1510              : 
    1511        44113 :    END SUBROUTINE qs_ot_get_derivative_taylor
    1512              : 
    1513              : ! *************************************************************************************************
    1514              : !> \brief computes a taylor expansion.
    1515              : !> \param qs_ot_env ...
    1516              : ! **************************************************************************************************
    1517        96281 :    SUBROUTINE qs_ot_p2m_taylor(qs_ot_env)
    1518              :       TYPE(qs_ot_type)                                   :: qs_ot_env
    1519              : 
    1520              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'qs_ot_p2m_taylor'
    1521              :       REAL(KIND=dp), PARAMETER                           :: rone = 1.0_dp, rzero = 0.0_dp
    1522              : 
    1523              :       INTEGER                                            :: handle, i, k
    1524              :       REAL(KIND=dp)                                      :: cosfactor, sinfactor
    1525              : 
    1526        59864 :       CALL timeset(routineN, handle)
    1527              : 
    1528              :       ! zeroth order
    1529        59864 :       CALL dbcsr_set(qs_ot_env%matrix_cosp, rzero)
    1530        59864 :       CALL dbcsr_set(qs_ot_env%matrix_sinp, rzero)
    1531        59864 :       CALL dbcsr_add_on_diag(qs_ot_env%matrix_cosp, rone)
    1532        59864 :       CALL dbcsr_add_on_diag(qs_ot_env%matrix_sinp, rone)
    1533              : 
    1534        59864 :       IF (qs_ot_env%taylor_order <= 0) THEN
    1535            0 :          CALL timestop(handle)
    1536        23447 :          RETURN
    1537              :       END IF
    1538              : 
    1539              :       ! first order
    1540        59864 :       cosfactor = -1.0_dp/(1.0_dp*2.0_dp)
    1541        59864 :       sinfactor = -1.0_dp/(2.0_dp*3.0_dp)
    1542        59864 :       CALL dbcsr_add(qs_ot_env%matrix_cosp, qs_ot_env%matrix_p, alpha_scalar=1.0_dp, beta_scalar=cosfactor)
    1543        59864 :       CALL dbcsr_add(qs_ot_env%matrix_sinp, qs_ot_env%matrix_p, alpha_scalar=1.0_dp, beta_scalar=sinfactor)
    1544        59864 :       IF (qs_ot_env%taylor_order <= 1) THEN
    1545        23447 :          CALL timestop(handle)
    1546        23447 :          RETURN
    1547              :       END IF
    1548              : 
    1549              :       ! other orders
    1550        36417 :       CALL dbcsr_get_info(qs_ot_env%matrix_p, nfullrows_total=k)
    1551        36417 :       CALL dbcsr_copy(qs_ot_env%matrix_r, qs_ot_env%matrix_p)
    1552              : 
    1553        92300 :       DO i = 2, qs_ot_env%taylor_order
    1554              :          ! new power of p
    1555              :          CALL dbcsr_multiply('N', 'N', rone, qs_ot_env%matrix_p, qs_ot_env%matrix_r, &
    1556        55883 :                              rzero, qs_ot_env%matrix_buf1)
    1557        55883 :          CALL dbcsr_copy(qs_ot_env%matrix_r, qs_ot_env%matrix_buf1)
    1558              :          ! add to the taylor expansion so far
    1559        55883 :          cosfactor = cosfactor*(-1.0_dp)/REAL(2*i*(2*i - 1), KIND=dp)
    1560        55883 :          sinfactor = sinfactor*(-1.0_dp)/REAL(2*i*(2*i + 1), KIND=dp)
    1561              :          CALL dbcsr_add(qs_ot_env%matrix_cosp, qs_ot_env%matrix_r, &
    1562        55883 :                         alpha_scalar=1.0_dp, beta_scalar=cosfactor)
    1563              :          CALL dbcsr_add(qs_ot_env%matrix_sinp, qs_ot_env%matrix_r, &
    1564        92300 :                         alpha_scalar=1.0_dp, beta_scalar=sinfactor)
    1565              :       END DO
    1566              : 
    1567        36417 :       CALL timestop(handle)
    1568              : 
    1569              :    END SUBROUTINE qs_ot_p2m_taylor
    1570              : 
    1571              : ! **************************************************************************************************
    1572              : !> \brief given p, computes  - eigenstuff (matrix_r,evals)
    1573              : !>        - cos(p^0.5),p^(-0.5)*sin(p^0.5)
    1574              : !>        - the real b matrices, needed for the derivatives of these guys
    1575              : !>        cosp_b_ij=(1/(2pii) * int(cos(z^1/2)/((z-eval(i))*(z-eval(j))))
    1576              : !>        sinp_b_ij=(1/(2pii) * int(z^(-1/2)*sin(z^1/2)/((z-eval(i))*(z-eval(j))))
    1577              : !> \param qs_ot_env ...
    1578              : ! **************************************************************************************************
    1579        52883 :    SUBROUTINE qs_ot_p2m_diag(qs_ot_env)
    1580              :       TYPE(qs_ot_type)                                   :: qs_ot_env
    1581              : 
    1582              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'qs_ot_p2m_diag'
    1583              : 
    1584              :       INTEGER                                            :: handle, phase
    1585              :       LOGICAL                                            :: cosine
    1586              :       TYPE(dbcsr_type), POINTER                          :: kernel, matrix, matrix_im
    1587              : 
    1588        52883 :       CALL timeset(routineN, handle)
    1589        52883 :       IF (qs_ot_env%has_complex_kpoint_state) THEN
    1590              :          CALL cp_dbcsr_heevd(matrix_re=qs_ot_env%matrix_p, matrix_im=qs_ot_env%matrix_p_im, &
    1591              :                              eigenvectors_re=qs_ot_env%matrix_r, eigenvectors_im=qs_ot_env%matrix_r_im, &
    1592              :                              eigenvalues=qs_ot_env%evals, para_env=qs_ot_env%para_env, &
    1593         1574 :                              blacs_env=qs_ot_env%blacs_env)
    1594              :       ELSE
    1595        51309 :          CALL dbcsr_copy(qs_ot_env%matrix_buf1, qs_ot_env%matrix_p)
    1596              :          CALL cp_dbcsr_syevd(qs_ot_env%matrix_buf1, qs_ot_env%matrix_r, qs_ot_env%evals, &
    1597        51309 :                              qs_ot_env%para_env, qs_ot_env%blacs_env)
    1598              :       END IF
    1599       541256 :       qs_ot_env%evals(:) = MAX(0.0_dp, qs_ot_env%evals(:))
    1600       158649 :       DO phase = 1, 2
    1601       105766 :          cosine = phase == 1
    1602       105766 :          IF (cosine) THEN
    1603        52883 :             matrix => qs_ot_env%matrix_cosp
    1604        52883 :             matrix_im => qs_ot_env%matrix_cosp_im
    1605        52883 :             kernel => qs_ot_env%matrix_cosp_b
    1606              :          ELSE
    1607        52883 :             matrix => qs_ot_env%matrix_sinp
    1608        52883 :             matrix_im => qs_ot_env%matrix_sinp_im
    1609        52883 :             kernel => qs_ot_env%matrix_sinp_b
    1610              :          END IF
    1611       105766 :          CALL qs_ot_spectral_values(qs_ot_env%evals, qs_ot_env%dum, cosine)
    1612       105766 :          CALL dbcsr_copy(qs_ot_env%matrix_buf1, qs_ot_env%matrix_r)
    1613       105766 :          CALL dbcsr_scale_by_vector(qs_ot_env%matrix_buf1, alpha=qs_ot_env%dum, side='right')
    1614       105766 :          IF (qs_ot_env%has_complex_kpoint_state) THEN
    1615         3148 :             CALL dbcsr_copy(qs_ot_env%matrix_buf1_im, qs_ot_env%matrix_r_im)
    1616         3148 :             CALL dbcsr_scale_by_vector(qs_ot_env%matrix_buf1_im, alpha=qs_ot_env%dum, side='right')
    1617              :             CALL qs_ot_complex_multiply('N', 'C', qs_ot_env%matrix_buf1, qs_ot_env%matrix_buf1_im, &
    1618              :                                         qs_ot_env%matrix_r, qs_ot_env%matrix_r_im, &
    1619         3148 :                                         matrix, matrix_im, qs_ot_env%matrix_buf2)
    1620              :          ELSE
    1621              :             ! Retain the original real-path operand order.
    1622       102618 :             CALL dbcsr_multiply('N', 'T', 1.0_dp, qs_ot_env%matrix_r, qs_ot_env%matrix_buf1, 0.0_dp, matrix)
    1623              :          END IF
    1624      1082512 :          qs_ot_env%dum(:) = SQRT(qs_ot_env%evals(:))
    1625       105766 :          CALL dbcsr_copy(kernel, matrix)
    1626       158649 :          CALL qs_ot_spectral_kernel_dbcsr(qs_ot_env%dum, kernel, cosine)
    1627              :       END DO
    1628        52883 :       CALL timestop(handle)
    1629        52883 :    END SUBROUTINE qs_ot_p2m_diag
    1630              : 
    1631              : ! **************************************************************************************************
    1632              : !> \brief Evaluate cos(sqrt(P)) or sinc(sqrt(P)) on the nonnegative eigenvalues of P.
    1633              : !> \param evals nonnegative eigenvalues
    1634              : !> \param values function values
    1635              : !> \param cosine select cosine; otherwise sinc
    1636              : ! **************************************************************************************************
    1637       109450 :    SUBROUTINE qs_ot_spectral_values(evals, values, cosine)
    1638              :       REAL(dp), INTENT(IN)                               :: evals(:)
    1639              :       REAL(dp), INTENT(OUT)                              :: values(:)
    1640              :       LOGICAL, INTENT(IN)                                :: cosine
    1641              : 
    1642              :       INTEGER                                            :: i
    1643              : 
    1644       109450 :       IF (cosine) THEN
    1645       552846 :          DO i = 1, SIZE(evals)
    1646       552846 :             values(i) = COS(SQRT(evals(i)))
    1647              :          END DO
    1648              :       ELSE
    1649       552846 :          DO i = 1, SIZE(evals)
    1650       552846 :             values(i) = qs_ot_sinc(SQRT(evals(i)))
    1651              :          END DO
    1652              :       END IF
    1653       109450 :    END SUBROUTINE qs_ot_spectral_values
    1654              : 
    1655              : ! **************************************************************************************************
    1656              : !> \brief Build a block of the real STRICT Frechet kernel, including coincident eigenvalues.
    1657              : !> \param roots_i square roots of the row eigenvalues
    1658              : !> \param roots_j square roots of the column eigenvalues
    1659              : !> \param block dense output block
    1660              : !> \param cosine select cosine; otherwise sinc
    1661              : ! **************************************************************************************************
    1662        78090 :    SUBROUTINE qs_ot_spectral_kernel(roots_i, roots_j, block, cosine)
    1663              :       REAL(dp), INTENT(IN)                               :: roots_i(:), roots_j(:)
    1664              :       REAL(dp), INTENT(OUT)                              :: block(:, :)
    1665              :       LOGICAL, INTENT(IN)                                :: cosine
    1666              : 
    1667              :       INTEGER                                            :: i, j
    1668              :       REAL(dp)                                           :: a, b
    1669              : 
    1670        78090 :       IF (cosine) THEN
    1671       516794 :          DO j = 1, SIZE(roots_j)
    1672     10869414 :          DO i = 1, SIZE(roots_i)
    1673     10352620 :             a = (roots_i(i) - roots_j(j))/2.0_dp
    1674     10352620 :             b = (roots_i(i) + roots_j(j))/2.0_dp
    1675     10830369 :             block(i, j) = -0.5_dp*qs_ot_sinc(a)*qs_ot_sinc(b)
    1676              :          END DO
    1677              :          END DO
    1678              :       ELSE
    1679       516794 :          DO j = 1, SIZE(roots_j)
    1680     10869414 :          DO i = 1, SIZE(roots_i)
    1681     10830369 :             block(i, j) = qs_ot_sincf(roots_i(i), roots_j(j))
    1682              :          END DO
    1683              :          END DO
    1684              :       END IF
    1685        78090 :    END SUBROUTINE qs_ot_spectral_kernel
    1686              : 
    1687              : ! **************************************************************************************************
    1688              : !> \brief Fill the existing blocks of a STRICT Frechet kernel with the shared dense formulas.
    1689              : !> \param roots square roots of the eigenvalues
    1690              : !> \param matrix distributed kernel
    1691              : !> \param cosine select cosine; otherwise sinc
    1692              : ! **************************************************************************************************
    1693       105766 :    SUBROUTINE qs_ot_spectral_kernel_dbcsr(roots, matrix, cosine)
    1694              :       REAL(dp), INTENT(IN)                               :: roots(:)
    1695              :       TYPE(dbcsr_type), INTENT(INOUT)                    :: matrix
    1696              :       LOGICAL, INTENT(IN)                                :: cosine
    1697              : 
    1698              :       INTEGER                                            :: col, nc, nr, row
    1699              :       LOGICAL                                            :: transposed
    1700       105766 :       REAL(dp), POINTER                                  :: block(:, :)
    1701              :       TYPE(dbcsr_iterator_type)                          :: iter
    1702              : 
    1703       105766 :       CALL dbcsr_iterator_start(iter, matrix)
    1704       180172 :       DO WHILE (dbcsr_iterator_blocks_left(iter))
    1705              :          CALL dbcsr_iterator_next_block(iter, block=block, transposed=transposed, &
    1706        74406 :                                         row_size=nr, col_size=nc, row_offset=row, col_offset=col)
    1707       180172 :          IF (transposed) THEN
    1708            0 :             CALL qs_ot_spectral_kernel(roots(col:col + nc - 1), roots(row:row + nr - 1), block, cosine)
    1709              :          ELSE
    1710        74406 :             CALL qs_ot_spectral_kernel(roots(row:row + nr - 1), roots(col:col + nc - 1), block, cosine)
    1711              :          END IF
    1712              :       END DO
    1713       105766 :       CALL dbcsr_iterator_stop(iter)
    1714       105766 :    END SUBROUTINE qs_ot_spectral_kernel_dbcsr
    1715              : 
    1716              : ! **************************************************************************************************
    1717              : !> \brief computes sin(x)/x for all values of the argument
    1718              : !> \param x ...
    1719              : !> \return ...
    1720              : ! **************************************************************************************************
    1721     28960463 :    FUNCTION qs_ot_sinc(x)
    1722              : 
    1723              :       REAL(KIND=dp), INTENT(IN)                          :: x
    1724              :       REAL(KIND=dp)                                      :: qs_ot_sinc
    1725              : 
    1726              :       REAL(KIND=dp), PARAMETER :: q1 = 1.0_dp, q2 = -q1/(2.0_dp*3.0_dp), q3 = -q2/(4.0_dp*5.0_dp), &
    1727              :          q4 = -q3/(6.0_dp*7.0_dp), q5 = -q4/(8.0_dp*9.0_dp), q6 = -q5/(10.0_dp*11.0_dp), &
    1728              :          q7 = -q6/(12.0_dp*13.0_dp), q8 = -q7/(14.0_dp*15.0_dp), q9 = -q8/(16.0_dp*17.0_dp), &
    1729              :          q10 = -q9/(18.0_dp*19.0_dp)
    1730              : 
    1731              :       REAL(KIND=dp)                                      :: y
    1732              : 
    1733     28960463 :       IF (ABS(x) > 0.5_dp) THEN
    1734      8718467 :          qs_ot_sinc = SIN(x)/x
    1735              :       ELSE
    1736     20241996 :          y = x*x
    1737     20241996 :          qs_ot_sinc = q1 + y*(q2 + y*(q3 + y*(q4 + y*(q5 + y*(q6 + y*(q7 + y*(q8 + y*(q9 + y*(q10)))))))))
    1738              :       END IF
    1739     28960463 :    END FUNCTION qs_ot_sinc
    1740              : 
    1741              : ! **************************************************************************************************
    1742              : !> \brief computes (1/(x^2-y^2))*(sinc(x)-sinc(y)) for all positive values of the arguments
    1743              : !> \param xa ...
    1744              : !> \param ya ...
    1745              : !> \return ...
    1746              : ! **************************************************************************************************
    1747     10352620 :    FUNCTION qs_ot_sincf(xa, ya)
    1748              : 
    1749              :       REAL(KIND=dp), INTENT(IN)                          :: xa, ya
    1750              :       REAL(KIND=dp)                                      :: qs_ot_sincf
    1751              : 
    1752              :       INTEGER                                            :: i
    1753              :       REAL(KIND=dp)                                      :: a, b, rs, sf, x, xs, y, ybx, ybxs
    1754              : 
    1755              :       ! this is currently a limit of the routine, could be removed rather easily
    1756     10352620 :       IF (xa < 0) CPABORT("x is negative")
    1757     10352620 :       IF (ya < 0) CPABORT("y is negative")
    1758              : 
    1759     10352620 :       IF (xa < ya) THEN
    1760      4949888 :          x = ya
    1761      4949888 :          y = xa
    1762              :       ELSE
    1763      5402732 :          x = xa
    1764      5402732 :          y = ya
    1765              :       END IF
    1766              : 
    1767     10352620 :       IF (x < 0.5_dp) THEN ! use series, keeping in mind that x,y,x+y,x-y can all be zero
    1768              : 
    1769      6474069 :          qs_ot_sincf = 0.0_dp
    1770      6474069 :          IF (x > 0.0_dp) THEN
    1771      6256886 :             ybx = y/x
    1772              :          ELSE ! should be irrelevant  !?
    1773              :             ybx = 0.0_dp
    1774              :          END IF
    1775              : 
    1776      6474069 :          sf = -1.0_dp/((1.0_dp + ybx)*6.0_dp)
    1777      6474069 :          rs = 1.0_dp
    1778      6474069 :          ybxs = ybx
    1779      6474069 :          xs = 1.0_dp
    1780              : 
    1781     71214759 :          DO i = 1, 10
    1782     64740690 :             qs_ot_sincf = qs_ot_sincf + sf*rs*xs*(1.0_dp + ybxs)
    1783     64740690 :             sf = -sf/(REAL((2*i + 2), dp)*REAL((2*i + 3), dp))
    1784     64740690 :             rs = rs + ybxs
    1785     64740690 :             ybxs = ybxs*ybx
    1786     71214759 :             xs = xs*x*x
    1787              :          END DO
    1788              : 
    1789              :       ELSE ! no series expansion
    1790      3878551 :          IF (x - y > 0.1_dp) THEN ! safe to use the normal form
    1791      3591678 :             qs_ot_sincf = (qs_ot_sinc(x) - qs_ot_sinc(y))/((x + y)*(x - y))
    1792              :          ELSE
    1793       286873 :             a = (x + y)/2.0_dp
    1794       286873 :             b = (x - y)/2.0_dp ! might be close to zero
    1795              :             ! y (=(a-b)) can not be close to zero since it is close to x>0.5
    1796       286873 :             qs_ot_sincf = (qs_ot_sinc(b)*COS(a) - qs_ot_sinc(a)*COS(b))/(2*x*y)
    1797              :          END IF
    1798              :       END IF
    1799              : 
    1800     10352620 :    END FUNCTION qs_ot_sincf
    1801              : 
    1802              : END MODULE qs_ot
        

Generated by: LCOV version 2.0-1