LCOV - code coverage report
Current view: top level - src - qs_ot.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:32ddf85) Lines: 581 616 94.3 %
Date: 2025-05-17 08:08:58 Functions: 23 23 100.0 %

          Line data    Source code
       1             : !--------------------------------------------------------------------------------------------------!
       2             : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3             : !   Copyright 2000-2025 CP2K developers group <https://cp2k.org>                                   !
       4             : !                                                                                                  !
       5             : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6             : !--------------------------------------------------------------------------------------------------!
       7             : 
       8             : ! **************************************************************************************************
       9             : !> \brief orbital transformations
      10             : !> \par History
      11             : !>      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_distribution_type, dbcsr_filter, dbcsr_get_block_p, &
      19             :         dbcsr_get_info, dbcsr_get_occupation, dbcsr_init_p, dbcsr_iterator_blocks_left, &
      20             :         dbcsr_iterator_next_block, dbcsr_iterator_start, dbcsr_iterator_stop, dbcsr_iterator_type, &
      21             :         dbcsr_multiply, dbcsr_release, dbcsr_release_p, dbcsr_scale, dbcsr_set, dbcsr_transposed, &
      22             :         dbcsr_type
      23             :    USE cp_dbcsr_cholesky,               ONLY: cp_dbcsr_cholesky_decompose,&
      24             :                                               cp_dbcsr_cholesky_invert,&
      25             :                                               cp_dbcsr_cholesky_restore
      26             :    USE cp_dbcsr_contrib,                ONLY: dbcsr_add_on_diag,&
      27             :                                               dbcsr_frobenius_norm,&
      28             :                                               dbcsr_gershgorin_norm,&
      29             :                                               dbcsr_hadamard_product,&
      30             :                                               dbcsr_scale_by_vector
      31             :    USE cp_dbcsr_diag,                   ONLY: cp_dbcsr_heevd,&
      32             :                                               cp_dbcsr_syevd
      33             :    USE kinds,                           ONLY: dp
      34             :    USE message_passing,                 ONLY: mp_comm_type
      35             :    USE preconditioner,                  ONLY: apply_preconditioner
      36             :    USE preconditioner_types,            ONLY: preconditioner_type
      37             :    USE qs_ot_types,                     ONLY: qs_ot_type
      38             : #include "./base/base_uses.f90"
      39             : 
      40             :    IMPLICIT NONE
      41             :    PRIVATE
      42             : 
      43             :    PUBLIC  :: qs_ot_get_p
      44             :    PUBLIC  :: qs_ot_get_orbitals
      45             :    PUBLIC  :: qs_ot_get_derivative
      46             :    PUBLIC  :: qs_ot_get_orbitals_ref
      47             :    PUBLIC  :: qs_ot_get_derivative_ref
      48             :    PUBLIC  :: qs_ot_new_preconditioner
      49             :    PRIVATE :: qs_ot_p2m_diag
      50             :    PRIVATE :: qs_ot_sinc
      51             :    PRIVATE :: qs_ot_ref_poly
      52             :    PRIVATE :: qs_ot_ref_chol
      53             :    PRIVATE :: qs_ot_ref_lwdn
      54             :    PRIVATE :: qs_ot_ref_decide
      55             :    PRIVATE :: qs_ot_ref_update
      56             :    PRIVATE :: qs_ot_refine
      57             :    PRIVATE :: qs_ot_on_the_fly_localize
      58             : 
      59             :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_ot'
      60             : 
      61             : CONTAINS
      62             : 
      63             : ! **************************************************************************************************
      64             : !> \brief gets ready to use the preconditioner/ or renew the preconditioner
      65             : !>        only keeps a pointer to the preconditioner.
      66             : !>        If you change the preconditioner, you have to call this routine
      67             : !>        you remain responsible of proper deallocate of your preconditioner
      68             : !>        (or you can reuse it on the next step of the computation)
      69             : !> \param qs_ot_env ...
      70             : !> \param preconditioner ...
      71             : ! **************************************************************************************************
      72        7398 :    SUBROUTINE qs_ot_new_preconditioner(qs_ot_env, preconditioner)
      73             :       TYPE(qs_ot_type)                                   :: qs_ot_env
      74             :       TYPE(preconditioner_type), POINTER                 :: preconditioner
      75             : 
      76             :       INTEGER                                            :: ncoef
      77             : 
      78        7398 :       qs_ot_env%preconditioner => preconditioner
      79        7398 :       qs_ot_env%os_valid = .FALSE.
      80        7398 :       IF (.NOT. ASSOCIATED(qs_ot_env%matrix_psc0)) THEN
      81        7398 :          CALL dbcsr_init_p(qs_ot_env%matrix_psc0)
      82        7398 :          CALL dbcsr_copy(qs_ot_env%matrix_psc0, qs_ot_env%matrix_sc0, 'matrix_psc0')
      83             :       END IF
      84             : 
      85        7398 :       IF (.NOT. qs_ot_env%use_dx) THEN
      86        4155 :          qs_ot_env%use_dx = .TRUE.
      87        4155 :          CALL dbcsr_init_p(qs_ot_env%matrix_dx)
      88        4155 :          CALL dbcsr_copy(qs_ot_env%matrix_dx, qs_ot_env%matrix_gx, 'matrix_dx')
      89        4155 :          IF (qs_ot_env%settings%do_rotation) THEN
      90          30 :             CALL dbcsr_init_p(qs_ot_env%rot_mat_dx)
      91          30 :             CALL dbcsr_copy(qs_ot_env%rot_mat_dx, qs_ot_env%rot_mat_gx, 'rot_mat_dx')
      92             :          END IF
      93        4155 :          IF (qs_ot_env%settings%do_ener) THEN
      94           0 :             ncoef = SIZE(qs_ot_env%ener_gx)
      95           0 :             ALLOCATE (qs_ot_env%ener_dx(ncoef))
      96           0 :             qs_ot_env%ener_dx = 0.0_dp
      97             :          END IF
      98             :       END IF
      99             : 
     100        7398 :    END SUBROUTINE qs_ot_new_preconditioner
     101             : 
     102             : ! **************************************************************************************************
     103             : !> \brief ...
     104             : !> \param qs_ot_env ...
     105             : !> \param C_NEW ...
     106             : !> \param SC ...
     107             : !> \param G_OLD ...
     108             : !> \param D ...
     109             : ! **************************************************************************************************
     110         420 :    SUBROUTINE qs_ot_on_the_fly_localize(qs_ot_env, C_NEW, SC, G_OLD, D)
     111             :       !
     112             :       TYPE(qs_ot_type)                                   :: qs_ot_env
     113             :       TYPE(dbcsr_type), POINTER                          :: C_NEW, SC, G_OLD, D
     114             : 
     115             :       CHARACTER(len=*), PARAMETER :: routineN = 'qs_ot_on_the_fly_localize'
     116             :       INTEGER, PARAMETER                                 :: taylor_order = 50
     117             :       REAL(KIND=dp), PARAMETER                           :: alpha = 0.1_dp, f2_eps = 0.01_dp
     118             : 
     119             :       INTEGER                                            :: col, col_size, handle, i, k, n, p, row, &
     120             :                                                             row_size
     121          84 :       REAL(dp), DIMENSION(:, :), POINTER                 :: block
     122             :       REAL(KIND=dp)                                      :: expfactor, f2, norm_fro, norm_gct, tmp
     123             :       TYPE(dbcsr_distribution_type)                      :: dist
     124             :       TYPE(dbcsr_iterator_type)                          :: iter
     125             :       TYPE(dbcsr_type), POINTER                          :: C, Gp1, Gp2, GU, U
     126             :       TYPE(mp_comm_type)                                 :: group
     127             : 
     128          84 :       CALL timeset(routineN, handle)
     129             :       !
     130             :       !
     131          84 :       CALL dbcsr_get_info(C_NEW, nfullrows_total=n, nfullcols_total=k)
     132             :       !
     133             :       ! C = C*expm(-G)
     134          84 :       GU => qs_ot_env%buf1_k_k_nosym ! a buffer
     135          84 :       U => qs_ot_env%buf2_k_k_nosym ! a buffer
     136          84 :       Gp1 => qs_ot_env%buf3_k_k_nosym ! a buffer
     137          84 :       Gp2 => qs_ot_env%buf4_k_k_nosym ! a buffer
     138          84 :       C => qs_ot_env%buf1_n_k ! a buffer
     139             :       !
     140             :       ! compute the derivative of the norm
     141             :       !-------------------------------------------------------------------
     142             :       ! (x^2+eps)^1/2
     143          84 :       f2 = 0.0_dp
     144          84 :       CALL dbcsr_copy(C, C_NEW)
     145          84 :       CALL dbcsr_iterator_start(iter, C)
     146         182 :       DO WHILE (dbcsr_iterator_blocks_left(iter))
     147          98 :          CALL dbcsr_iterator_next_block(iter, row, col, block, row_size=row_size, col_size=col_size)
     148         686 :          DO p = 1, col_size ! p
     149        6258 :          DO i = 1, row_size ! i
     150        5656 :             tmp = SQRT(block(i, p)**2 + f2_eps)
     151        5656 :             f2 = f2 + tmp
     152        6160 :             block(i, p) = block(i, p)/tmp
     153             :          END DO
     154             :          END DO
     155             :       END DO
     156          84 :       CALL dbcsr_iterator_stop(iter)
     157          84 :       CALL dbcsr_get_info(C, group=group)
     158          84 :       CALL group%sum(f2)
     159             :       !
     160             :       !
     161          84 :       CALL dbcsr_multiply('T', 'N', 1.0_dp, C, C_NEW, 0.0_dp, GU)
     162             :       !
     163             :       ! antisymetrize
     164          84 :       CALL dbcsr_get_info(GU, distribution=dist)
     165             :       CALL dbcsr_transposed(U, GU, shallow_data_copy=.FALSE., &
     166             :                             use_distribution=dist, &
     167          84 :                             transpose_distribution=.FALSE.)
     168          84 :       CALL dbcsr_add(GU, U, alpha_scalar=-0.5_dp, beta_scalar=0.5_dp)
     169             :       !-------------------------------------------------------------------
     170             :       !
     171          84 :       norm_fro = dbcsr_frobenius_norm(GU)
     172          84 :       norm_gct = dbcsr_gershgorin_norm(GU)
     173             :       !write(*,*) 'qs_ot_localize: ||P-I||_f=',norm_fro,' ||P-I||_GCT=',norm_gct
     174             :       !
     175             :       !kscale = CEILING(LOG(MIN(norm_fro,norm_gct))/LOG(2.0_dp))
     176             :       !scale  = LOG(MIN(norm_fro,norm_gct))/LOG(2.0_dp)
     177             :       !write(*,*) 'qs_ot_localize: scale=',scale,' kscale=',kscale
     178             :       !
     179             :       ! rescale for steepest descent
     180          84 :       CALL dbcsr_scale(GU, -alpha)
     181             :       !
     182             :       ! compute unitary transform
     183             :       ! zeroth and first order
     184          84 :       expfactor = 1.0_dp
     185          84 :       CALL dbcsr_copy(U, GU)
     186          84 :       CALL dbcsr_scale(U, expfactor)
     187          84 :       CALL dbcsr_add_on_diag(U, 1.0_dp)
     188             :       ! other orders
     189          84 :       CALL dbcsr_copy(Gp1, GU)
     190         520 :       DO i = 2, taylor_order
     191             :          ! new power of G
     192         520 :          CALL dbcsr_multiply('N', 'N', 1.0_dp, GU, Gp1, 0.0_dp, Gp2)
     193         520 :          CALL dbcsr_copy(Gp1, Gp2)
     194             :          ! add to the taylor expansion so far
     195         520 :          expfactor = expfactor/REAL(i, KIND=dp)
     196         520 :          CALL dbcsr_add(U, Gp1, alpha_scalar=1.0_dp, beta_scalar=expfactor)
     197         520 :          norm_fro = dbcsr_frobenius_norm(Gp1)
     198             :          !write(*,*) 'Taylor expansion i=',i,' norm(X^i)/i!=',norm_fro*expfactor
     199         520 :          IF (norm_fro*expfactor .LT. 1.0E-10_dp) EXIT
     200             :       END DO
     201             :       !
     202             :       ! rotate MOs
     203          84 :       CALL dbcsr_multiply('N', 'N', 1.0_dp, C_NEW, U, 0.0_dp, C)
     204          84 :       CALL dbcsr_copy(C_NEW, C)
     205             :       !
     206             :       ! rotate SC
     207          84 :       CALL dbcsr_multiply('N', 'N', 1.0_dp, SC, U, 0.0_dp, C)
     208          84 :       CALL dbcsr_copy(SC, C)
     209             :       !
     210             :       ! rotate D_i
     211          84 :       CALL dbcsr_multiply('N', 'N', 1.0_dp, D, U, 0.0_dp, C)
     212          84 :       CALL dbcsr_copy(D, C)
     213             :       !
     214             :       ! rotate G_i-1
     215          84 :       IF (ASSOCIATED(G_OLD)) THEN
     216          84 :          CALL dbcsr_multiply('N', 'N', 1.0_dp, G_OLD, U, 0.0_dp, C)
     217          84 :          CALL dbcsr_copy(G_OLD, C)
     218             :       END IF
     219             :       !
     220          84 :       CALL timestop(handle)
     221          84 :    END SUBROUTINE qs_ot_on_the_fly_localize
     222             : 
     223             : ! **************************************************************************************************
     224             : !> \brief ...
     225             : !> \param qs_ot_env ...
     226             : !> \param C_OLD ...
     227             : !> \param C_TMP ...
     228             : !> \param C_NEW ...
     229             : !> \param P ...
     230             : !> \param SC ...
     231             : !> \param update ...
     232             : ! **************************************************************************************************
     233        1492 :    SUBROUTINE qs_ot_ref_chol(qs_ot_env, C_OLD, C_TMP, C_NEW, P, SC, update)
     234             :       !
     235             :       TYPE(qs_ot_type)                                   :: qs_ot_env
     236             :       TYPE(dbcsr_type)                                   :: C_OLD, C_TMP, C_NEW, P, SC
     237             :       LOGICAL, INTENT(IN)                                :: update
     238             : 
     239             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'qs_ot_ref_chol'
     240             : 
     241             :       INTEGER                                            :: handle, k, n
     242             : 
     243         746 :       CALL timeset(routineN, handle)
     244             :       !
     245         746 :       CALL dbcsr_get_info(C_NEW, nfullrows_total=n, nfullcols_total=k)
     246             :       !
     247             :       ! P = U'*U
     248         746 :       CALL cp_dbcsr_cholesky_decompose(P, k, qs_ot_env%para_env, qs_ot_env%blacs_env)
     249             :       !
     250             :       ! C_NEW = C_OLD*inv(U)
     251             :       CALL cp_dbcsr_cholesky_restore(C_OLD, k, P, C_NEW, op="SOLVE", pos="RIGHT", &
     252         746 :                                      transa="N", para_env=qs_ot_env%para_env, blacs_env=qs_ot_env%blacs_env)
     253             :       !
     254             :       ! Update SC if needed
     255         746 :       IF (update) THEN
     256             :          CALL cp_dbcsr_cholesky_restore(SC, k, P, C_TMP, op="SOLVE", pos="RIGHT", &
     257         414 :                                         transa="N", para_env=qs_ot_env%para_env, blacs_env=qs_ot_env%blacs_env)
     258         414 :          CALL dbcsr_copy(SC, C_TMP)
     259             :       END IF
     260             :       !
     261         746 :       CALL timestop(handle)
     262         746 :    END SUBROUTINE qs_ot_ref_chol
     263             : 
     264             : ! **************************************************************************************************
     265             : !> \brief ...
     266             : !> \param qs_ot_env ...
     267             : !> \param C_OLD ...
     268             : !> \param C_TMP ...
     269             : !> \param C_NEW ...
     270             : !> \param P ...
     271             : !> \param SC ...
     272             : !> \param update ...
     273             : ! **************************************************************************************************
     274         308 :    SUBROUTINE qs_ot_ref_lwdn(qs_ot_env, C_OLD, C_TMP, C_NEW, P, SC, update)
     275             :       !
     276             :       TYPE(qs_ot_type)                                   :: qs_ot_env
     277             :       TYPE(dbcsr_type)                                   :: C_OLD, C_TMP, C_NEW, P, SC
     278             :       LOGICAL, INTENT(IN)                                :: update
     279             : 
     280             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'qs_ot_ref_lwdn'
     281             : 
     282             :       INTEGER                                            :: handle, i, k, n
     283             :       REAL(dp), ALLOCATABLE, DIMENSION(:)                :: eig, fun
     284             :       TYPE(dbcsr_type), POINTER                          :: V, W
     285             : 
     286         308 :       CALL timeset(routineN, handle)
     287             :       !
     288         308 :       CALL dbcsr_get_info(C_NEW, nfullrows_total=n, nfullcols_total=k)
     289             :       !
     290         308 :       V => qs_ot_env%buf1_k_k_nosym ! a buffer
     291         308 :       W => qs_ot_env%buf2_k_k_nosym ! a buffer
     292        1232 :       ALLOCATE (eig(k), fun(k))
     293             :       !
     294         308 :       CALL cp_dbcsr_syevd(P, V, eig, qs_ot_env%para_env, qs_ot_env%blacs_env)
     295             :       !
     296             :       ! compute the P^(-1/2)
     297        1796 :       DO i = 1, k
     298        1488 :          IF (eig(i) .LE. 0.0_dp) &
     299           0 :             CPABORT("P not positive definite")
     300        1796 :          IF (eig(i) .LT. 1.0E-8_dp) THEN
     301           0 :             fun(i) = 0.0_dp
     302             :          ELSE
     303        1488 :             fun(i) = 1.0_dp/SQRT(eig(i))
     304             :          END IF
     305             :       END DO
     306         308 :       CALL dbcsr_copy(W, V)
     307         308 :       CALL dbcsr_scale_by_vector(V, alpha=fun, side='right')
     308         308 :       CALL dbcsr_multiply('N', 'T', 1.0_dp, W, V, 0.0_dp, P)
     309             :       !
     310             :       ! Update C
     311         308 :       CALL dbcsr_multiply('N', 'N', 1.0_dp, C_OLD, P, 0.0_dp, C_NEW)
     312             :       !
     313             :       ! Update SC if needed
     314         308 :       IF (update) THEN
     315         216 :          CALL dbcsr_multiply('N', 'N', 1.0_dp, SC, P, 0.0_dp, C_TMP)
     316         216 :          CALL dbcsr_copy(SC, C_TMP)
     317             :       END IF
     318             :       !
     319         308 :       DEALLOCATE (eig, fun)
     320             :       !
     321         308 :       CALL timestop(handle)
     322         308 :    END SUBROUTINE qs_ot_ref_lwdn
     323             : 
     324             : ! **************************************************************************************************
     325             : !> \brief ...
     326             : !> \param qs_ot_env ...
     327             : !> \param C_OLD ...
     328             : !> \param C_TMP ...
     329             : !> \param C_NEW ...
     330             : !> \param P ...
     331             : !> \param SC ...
     332             : !> \param norm_in ...
     333             : !> \param update ...
     334             : ! **************************************************************************************************
     335        7104 :    SUBROUTINE qs_ot_ref_poly(qs_ot_env, C_OLD, C_TMP, C_NEW, P, SC, norm_in, update)
     336             :       !
     337             :       TYPE(qs_ot_type)                                   :: qs_ot_env
     338             :       TYPE(dbcsr_type), POINTER                          :: C_OLD, C_TMP, C_NEW, P
     339             :       TYPE(dbcsr_type)                                   :: SC
     340             :       REAL(dp), INTENT(IN)                               :: norm_in
     341             :       LOGICAL, INTENT(IN)                                :: update
     342             : 
     343             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'qs_ot_ref_poly'
     344             : 
     345             :       INTEGER                                            :: handle, irefine, k, n
     346             :       LOGICAL                                            :: quick_exit
     347             :       REAL(dp)                                           :: norm, norm_fro, norm_gct, occ_in, &
     348             :                                                             occ_out, rescale
     349             :       TYPE(dbcsr_type), POINTER                          :: BUF1, BUF2, BUF_NOSYM, FT, FY
     350             : 
     351        3552 :       CALL timeset(routineN, handle)
     352             :       !
     353        3552 :       CALL dbcsr_get_info(C_NEW, nfullrows_total=n, nfullcols_total=k)
     354             :       !
     355        3552 :       BUF_NOSYM => qs_ot_env%buf1_k_k_nosym ! a buffer
     356        3552 :       BUF1 => qs_ot_env%buf1_k_k_sym ! a buffer
     357        3552 :       BUF2 => qs_ot_env%buf2_k_k_sym ! a buffer
     358        3552 :       FY => qs_ot_env%buf3_k_k_sym ! a buffer
     359        3552 :       FT => qs_ot_env%buf4_k_k_sym ! a buffer
     360             :       !
     361             :       ! initialize the norm (already computed in qs_ot_get_orbitals_ref)
     362        3552 :       norm = norm_in
     363             :       !
     364             :       ! can we do a quick exit?
     365        3552 :       quick_exit = .FALSE.
     366        3552 :       IF (norm .LT. qs_ot_env%settings%eps_irac_quick_exit) quick_exit = .TRUE.
     367             :       !
     368             :       ! lets refine
     369        3552 :       rescale = 1.0_dp
     370        3986 :       DO irefine = 1, qs_ot_env%settings%max_irac
     371             :          !
     372             :          ! rescaling
     373        3986 :          IF (norm .GT. 1.0_dp) THEN
     374          12 :             CALL dbcsr_scale(P, 1.0_dp/norm)
     375          12 :             rescale = rescale/SQRT(norm)
     376             :          END IF
     377             :          !
     378             :          ! get the refinement polynomial
     379             :          CALL qs_ot_refine(P, FY, BUF1, BUF2, qs_ot_env%settings%irac_degree, &
     380        3986 :                            qs_ot_env%settings%eps_irac_filter_matrix)
     381             :          !
     382             :          ! collect the transformation
     383        3986 :          IF (irefine .EQ. 1) THEN
     384        3552 :             CALL dbcsr_copy(FT, FY, name='FT')
     385             :          ELSE
     386         434 :             CALL dbcsr_multiply('N', 'N', 1.0_dp, FT, FY, 0.0_dp, BUF1)
     387         434 :             IF (qs_ot_env%settings%eps_irac_filter_matrix .GT. 0.0_dp) THEN
     388           4 :                occ_in = dbcsr_get_occupation(buf1)
     389           4 :                CALL dbcsr_filter(buf1, qs_ot_env%settings%eps_irac_filter_matrix)
     390           4 :                occ_out = dbcsr_get_occupation(buf1)
     391             :             END IF
     392         434 :             CALL dbcsr_copy(FT, BUF1, name='FT')
     393             :          END IF
     394             :          !
     395             :          ! quick exit if possible
     396        3986 :          IF (quick_exit) THEN
     397             :             EXIT
     398             :          END IF
     399             :          !
     400             :          ! P = FY^T * P * FY
     401        1712 :          CALL dbcsr_multiply('N', 'N', 1.0_dp, P, FY, 0.0_dp, BUF_NOSYM)
     402        1712 :          IF (qs_ot_env%settings%eps_irac_filter_matrix .GT. 0.0_dp) THEN
     403           8 :             occ_in = dbcsr_get_occupation(buf_nosym)
     404           8 :             CALL dbcsr_filter(buf_nosym, qs_ot_env%settings%eps_irac_filter_matrix)
     405           8 :             occ_out = dbcsr_get_occupation(buf_nosym)
     406             :          END IF
     407        1712 :          CALL dbcsr_multiply('N', 'N', 1.0_dp, FY, BUF_NOSYM, 0.0_dp, P)
     408        1712 :          IF (qs_ot_env%settings%eps_irac_filter_matrix .GT. 0.0_dp) THEN
     409           8 :             occ_in = dbcsr_get_occupation(p)
     410           8 :             CALL dbcsr_filter(p, qs_ot_env%settings%eps_irac_filter_matrix)
     411           8 :             occ_out = dbcsr_get_occupation(p)
     412             :          END IF
     413             :          !
     414             :          ! check ||P-1||_gct
     415        1712 :          CALL dbcsr_add_on_diag(P, -1.0_dp)
     416        1712 :          norm_fro = dbcsr_frobenius_norm(P)
     417        1712 :          norm_gct = dbcsr_gershgorin_norm(P)
     418        1712 :          CALL dbcsr_add_on_diag(P, 1.0_dp)
     419        1712 :          norm = MIN(norm_gct, norm_fro)
     420             :          !
     421             :          ! printing
     422             :          !
     423             :          ! blows up
     424        1712 :          IF (norm > 1.0E10_dp) THEN
     425             :             CALL cp_abort(__LOCATION__, &
     426             :                           "Refinement blows up! "// &
     427             :                           "We need you to improve the code, please post your input on "// &
     428           0 :                           "the forum https://www.cp2k.org/")
     429             :          END IF
     430             :          !
     431             :          ! can we do a quick exit next step?
     432        1712 :          IF (norm .LT. qs_ot_env%settings%eps_irac_quick_exit) quick_exit = .TRUE.
     433             :          !
     434             :          ! are we done?
     435        3986 :          IF (norm .LT. qs_ot_env%settings%eps_irac) EXIT
     436             :          !
     437             :       END DO
     438             :       !
     439             :       ! C_NEW = C_NEW * FT * rescale
     440        3552 :       CALL dbcsr_multiply('N', 'N', rescale, C_OLD, FT, 0.0_dp, C_NEW)
     441        3552 :       IF (qs_ot_env%settings%eps_irac_filter_matrix .GT. 0.0_dp) THEN
     442           4 :          occ_in = dbcsr_get_occupation(c_new)
     443           4 :          CALL dbcsr_filter(c_new, qs_ot_env%settings%eps_irac_filter_matrix)
     444           4 :          occ_out = dbcsr_get_occupation(c_new)
     445             :       END IF
     446             :       !
     447             :       ! update SC = SC * FY * rescale
     448        3552 :       IF (update) THEN
     449        1412 :          CALL dbcsr_multiply('N', 'N', rescale, SC, FT, 0.0_dp, C_TMP)
     450        1412 :          IF (qs_ot_env%settings%eps_irac_filter_matrix .GT. 0.0_dp) THEN
     451           4 :             occ_in = dbcsr_get_occupation(c_tmp)
     452           4 :             CALL dbcsr_filter(c_tmp, qs_ot_env%settings%eps_irac_filter_matrix)
     453           4 :             occ_out = dbcsr_get_occupation(c_tmp)
     454             :          END IF
     455        1412 :          CALL dbcsr_copy(SC, C_TMP)
     456             :       END IF
     457             :       !
     458        3552 :       CALL timestop(handle)
     459        3552 :    END SUBROUTINE qs_ot_ref_poly
     460             : 
     461             : ! **************************************************************************************************
     462             : !> \brief ...
     463             : !> \param qs_ot_env1 ...
     464             : !> \return ...
     465             : ! **************************************************************************************************
     466        4606 :    FUNCTION qs_ot_ref_update(qs_ot_env1) RESULT(update)
     467             :       !
     468             :       TYPE(qs_ot_type)                                   :: qs_ot_env1
     469             :       LOGICAL                                            :: update
     470             : 
     471        4606 :       update = .FALSE.
     472        4174 :       SELECT CASE (qs_ot_env1%settings%ot_method)
     473             :       CASE ("CG")
     474        4174 :          SELECT CASE (qs_ot_env1%settings%line_search_method)
     475             :          CASE ("2PNT")
     476        4174 :             IF (qs_ot_env1%line_search_count .EQ. 2) update = .TRUE.
     477             :          CASE DEFAULT
     478        4174 :             CPABORT("NYI")
     479             :          END SELECT
     480             :       CASE ("DIIS")
     481           0 :          update = .TRUE.
     482             :       CASE DEFAULT
     483        4606 :          CPABORT("NYI")
     484             :       END SELECT
     485        4606 :    END FUNCTION qs_ot_ref_update
     486             : 
     487             : ! **************************************************************************************************
     488             : !> \brief ...
     489             : !> \param qs_ot_env1 ...
     490             : !> \param norm_in ...
     491             : !> \param ortho_irac ...
     492             : ! **************************************************************************************************
     493        4606 :    SUBROUTINE qs_ot_ref_decide(qs_ot_env1, norm_in, ortho_irac)
     494             :       !
     495             :       TYPE(qs_ot_type)                                   :: qs_ot_env1
     496             :       REAL(dp), INTENT(IN)                               :: norm_in
     497             :       CHARACTER(LEN=*), INTENT(INOUT)                    :: ortho_irac
     498             : 
     499        4606 :       ortho_irac = qs_ot_env1%settings%ortho_irac
     500        4606 :       IF (norm_in .LT. qs_ot_env1%settings%eps_irac_switch) ortho_irac = "POLY"
     501        4606 :    END SUBROUTINE qs_ot_ref_decide
     502             : 
     503             : ! **************************************************************************************************
     504             : !> \brief ...
     505             : !> \param matrix_c ...
     506             : !> \param matrix_s ...
     507             : !> \param matrix_x ...
     508             : !> \param matrix_sx ...
     509             : !> \param matrix_gx_old ...
     510             : !> \param matrix_dx ...
     511             : !> \param qs_ot_env ...
     512             : !> \param qs_ot_env1 ...
     513             : ! **************************************************************************************************
     514        9212 :    SUBROUTINE qs_ot_get_orbitals_ref(matrix_c, matrix_s, matrix_x, matrix_sx, &
     515             :                                      matrix_gx_old, matrix_dx, qs_ot_env, qs_ot_env1)
     516             :       !
     517             :       TYPE(dbcsr_type), POINTER                          :: matrix_c, matrix_s, matrix_x, matrix_sx, &
     518             :                                                             matrix_gx_old, matrix_dx
     519             :       TYPE(qs_ot_type)                                   :: qs_ot_env, qs_ot_env1
     520             : 
     521             :       CHARACTER(len=*), PARAMETER :: routineN = 'qs_ot_get_orbitals_ref'
     522             : 
     523             :       CHARACTER(LEN=4)                                   :: ortho_irac
     524             :       INTEGER                                            :: handle, k, n
     525             :       LOGICAL                                            :: on_the_fly_loc, update
     526             :       REAL(dp)                                           :: norm, norm_fro, norm_gct, occ_in, occ_out
     527             :       TYPE(dbcsr_type), POINTER                          :: C_NEW, C_OLD, C_TMP, D, G_OLD, P, S, SC
     528             : 
     529        4606 :       CALL timeset(routineN, handle)
     530             : 
     531        4606 :       CALL dbcsr_get_info(matrix_c, nfullrows_total=n, nfullcols_total=k)
     532             :       !
     533        4606 :       C_NEW => matrix_c
     534        4606 :       C_OLD => matrix_x ! need to be carefully updated for the gradient !
     535        4606 :       SC => matrix_sx ! need to be carefully updated for the gradient !
     536        4606 :       G_OLD => matrix_gx_old ! need to be carefully updated for localization !
     537        4606 :       D => matrix_dx ! need to be carefully updated for localization !
     538        4606 :       S => matrix_s
     539             : 
     540        4606 :       P => qs_ot_env%p_k_k_sym ! a buffer
     541        4606 :       C_TMP => qs_ot_env%buf1_n_k ! a buffer
     542             :       !
     543             :       ! do we need to update C_OLD and SC?
     544        4606 :       update = qs_ot_ref_update(qs_ot_env1)
     545             :       !
     546             :       ! do we want to on the fly localize?
     547             :       ! for the moment this is set from the input,
     548             :       ! later we might want to localize every n-step or
     549             :       ! when the sparsity increases...
     550        4606 :       on_the_fly_loc = qs_ot_env1%settings%on_the_fly_loc
     551             :       !
     552             :       ! compute SC = S*C
     553        4606 :       IF (ASSOCIATED(S)) THEN
     554        4606 :          CALL dbcsr_multiply('N', 'N', 1.0_dp, S, C_OLD, 0.0_dp, SC)
     555        4606 :          IF (qs_ot_env1%settings%eps_irac_filter_matrix .GT. 0.0_dp) THEN
     556           4 :             occ_in = dbcsr_get_occupation(sc)
     557           4 :             CALL dbcsr_filter(sc, qs_ot_env1%settings%eps_irac_filter_matrix)
     558           4 :             occ_out = dbcsr_get_occupation(sc)
     559             :          END IF
     560             :       ELSE
     561           0 :          CALL dbcsr_copy(SC, C_OLD)
     562             :       END IF
     563             :       !
     564             :       ! compute P = C'*SC
     565        4606 :       CALL dbcsr_multiply('T', 'N', 1.0_dp, C_OLD, SC, 0.0_dp, P)
     566        4606 :       IF (qs_ot_env1%settings%eps_irac_filter_matrix .GT. 0.0_dp) THEN
     567           4 :          occ_in = dbcsr_get_occupation(p)
     568           4 :          CALL dbcsr_filter(p, qs_ot_env1%settings%eps_irac_filter_matrix)
     569           4 :          occ_out = dbcsr_get_occupation(p)
     570             :       END IF
     571             :       !
     572             :       ! check ||P-1||_f and ||P-1||_gct
     573        4606 :       CALL dbcsr_add_on_diag(P, -1.0_dp)
     574        4606 :       norm_fro = dbcsr_frobenius_norm(P)
     575        4606 :       norm_gct = dbcsr_gershgorin_norm(P)
     576        4606 :       CALL dbcsr_add_on_diag(P, 1.0_dp)
     577        4606 :       norm = MIN(norm_gct, norm_fro)
     578        4606 :       CALL qs_ot_ref_decide(qs_ot_env1, norm, ortho_irac)
     579             :       !
     580             :       ! select the orthogonality method
     581         746 :       SELECT CASE (ortho_irac)
     582             :       CASE ("CHOL")
     583         746 :          CALL qs_ot_ref_chol(qs_ot_env, C_OLD, C_TMP, C_NEW, P, SC, update)
     584             :       CASE ("LWDN")
     585         308 :          CALL qs_ot_ref_lwdn(qs_ot_env, C_OLD, C_TMP, C_NEW, P, SC, update)
     586             :       CASE ("POLY")
     587        3552 :          CALL qs_ot_ref_poly(qs_ot_env, C_OLD, C_TMP, C_NEW, P, SC, norm, update)
     588             :       CASE DEFAULT
     589        4606 :          CPABORT("Wrong argument")
     590             :       END SELECT
     591             :       !
     592             :       ! We update the C_i+1 and localization
     593        4606 :       IF (update) THEN
     594        2042 :          IF (on_the_fly_loc) THEN
     595          84 :             CALL qs_ot_on_the_fly_localize(qs_ot_env, C_NEW, SC, G_OLD, D)
     596             :          END IF
     597        2042 :          CALL dbcsr_copy(C_OLD, C_NEW)
     598             :       END IF
     599             :       !
     600        4606 :       CALL timestop(handle)
     601        4606 :    END SUBROUTINE qs_ot_get_orbitals_ref
     602             : 
     603             : ! **************************************************************************************************
     604             : !> \brief  refinement polynomial of degree 2,3 and 4 (PRB 70, 193102 (2004))
     605             : !> \param P ...
     606             : !> \param FY ...
     607             : !> \param P2 ...
     608             : !> \param T ...
     609             : !> \param irac_degree ...
     610             : !> \param eps_irac_filter_matrix ...
     611             : ! **************************************************************************************************
     612        7972 :    SUBROUTINE qs_ot_refine(P, FY, P2, T, irac_degree, eps_irac_filter_matrix)
     613             :       TYPE(dbcsr_type), INTENT(inout)                    :: P, FY, P2, T
     614             :       INTEGER, INTENT(in)                                :: irac_degree
     615             :       REAL(dp), INTENT(in)                               :: eps_irac_filter_matrix
     616             : 
     617             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'qs_ot_refine'
     618             : 
     619             :       INTEGER                                            :: handle, k
     620             :       REAL(dp)                                           :: occ_in, occ_out, r
     621             : 
     622        3986 :       CALL timeset(routineN, handle)
     623             : 
     624        3986 :       CALL dbcsr_get_info(P, nfullcols_total=k)
     625        3986 :       SELECT CASE (irac_degree)
     626             :       CASE (2)
     627             :          ! C_out = C_in * ( 15/8 * I - 10/8 * P + 3/8 * P^2)
     628           0 :          r = 3.0_dp/8.0_dp
     629           0 :          CALL dbcsr_multiply('N', 'N', r, P, P, 0.0_dp, FY)
     630           0 :          IF (eps_irac_filter_matrix .GT. 0.0_dp) THEN
     631           0 :             occ_in = dbcsr_get_occupation(fy)
     632           0 :             CALL dbcsr_filter(fy, eps_irac_filter_matrix)
     633           0 :             occ_out = dbcsr_get_occupation(fy)
     634             :          END IF
     635           0 :          r = -10.0_dp/8.0_dp
     636           0 :          CALL dbcsr_add(FY, P, alpha_scalar=1.0_dp, beta_scalar=r)
     637           0 :          r = 15.0_dp/8.0_dp
     638           0 :          CALL dbcsr_add_on_diag(FY, alpha=r)
     639             :       CASE (3)
     640             :          ! C_out = C_in * ( 35/16 * I - 35/16 * P + 21/16 * P^2 - 5/16 P^3)
     641           0 :          CALL dbcsr_multiply('N', 'N', 1.0_dp, P, P, 0.0_dp, P2)
     642           0 :          IF (eps_irac_filter_matrix .GT. 0.0_dp) THEN
     643           0 :             occ_in = dbcsr_get_occupation(p2)
     644           0 :             CALL dbcsr_filter(p2, eps_irac_filter_matrix)
     645           0 :             occ_out = dbcsr_get_occupation(p2)
     646             :          END IF
     647           0 :          r = -5.0_dp/16.0_dp
     648           0 :          CALL dbcsr_multiply('N', 'N', r, P2, P, 0.0_dp, FY)
     649           0 :          IF (eps_irac_filter_matrix .GT. 0.0_dp) THEN
     650           0 :             occ_in = dbcsr_get_occupation(fy)
     651           0 :             CALL dbcsr_filter(fy, eps_irac_filter_matrix)
     652           0 :             occ_out = dbcsr_get_occupation(fy)
     653             :          END IF
     654           0 :          r = 21.0_dp/16.0_dp
     655           0 :          CALL dbcsr_add(FY, P2, alpha_scalar=1.0_dp, beta_scalar=r)
     656           0 :          r = -35.0_dp/16.0_dp
     657           0 :          CALL dbcsr_add(FY, P, alpha_scalar=1.0_dp, beta_scalar=r)
     658           0 :          r = 35.0_dp/16.0_dp
     659           0 :          CALL dbcsr_add_on_diag(FY, alpha=r)
     660             :       CASE (4)
     661             :          ! C_out = C_in * ( 315/128 * I - 420/128 * P + 378/128 * P^2 - 180/128 P^3 + 35/128 P^4 )
     662             :          !       = C_in * ( 315/128 * I - 420/128 * P + 378/128 * P^2 + ( - 180/128 * P + 35/128 * P^2 ) * P^2 )
     663        3986 :          CALL dbcsr_multiply('N', 'N', 1.0_dp, P, P, 0.0_dp, P2) ! P^2
     664        3986 :          IF (eps_irac_filter_matrix .GT. 0.0_dp) THEN
     665           8 :             occ_in = dbcsr_get_occupation(p2)
     666           8 :             CALL dbcsr_filter(p2, eps_irac_filter_matrix)
     667           8 :             occ_out = dbcsr_get_occupation(p2)
     668             :          END IF
     669        3986 :          r = -180.0_dp/128.0_dp
     670        3986 :          CALL dbcsr_add(T, P, alpha_scalar=0.0_dp, beta_scalar=r) ! T=-180/128*P
     671        3986 :          r = 35.0_dp/128.0_dp
     672        3986 :          CALL dbcsr_add(T, P2, alpha_scalar=1.0_dp, beta_scalar=r) ! T=T+35/128*P^2
     673        3986 :          CALL dbcsr_multiply('N', 'N', 1.0_dp, T, P2, 0.0_dp, FY) ! Y=T*P^2
     674        3986 :          IF (eps_irac_filter_matrix .GT. 0.0_dp) THEN
     675           8 :             occ_in = dbcsr_get_occupation(fy)
     676           8 :             CALL dbcsr_filter(fy, eps_irac_filter_matrix)
     677           8 :             occ_out = dbcsr_get_occupation(fy)
     678             :          END IF
     679        3986 :          r = 378.0_dp/128.0_dp
     680        3986 :          CALL dbcsr_add(FY, P2, alpha_scalar=1.0_dp, beta_scalar=r) ! Y=Y+378/128*P^2
     681        3986 :          r = -420.0_dp/128.0_dp
     682        3986 :          CALL dbcsr_add(FY, P, alpha_scalar=1.0_dp, beta_scalar=r) ! Y=Y-420/128*P
     683        3986 :          r = 315.0_dp/128.0_dp
     684        3986 :          CALL dbcsr_add_on_diag(FY, alpha=r) ! Y=Y+315/128*I
     685             :       CASE DEFAULT
     686        3986 :          CPABORT("This irac_order NYI")
     687             :       END SELECT
     688        3986 :       CALL timestop(handle)
     689        3986 :    END SUBROUTINE qs_ot_refine
     690             : 
     691             : ! **************************************************************************************************
     692             : !> \brief ...
     693             : !> \param matrix_hc ...
     694             : !> \param matrix_x ...
     695             : !> \param matrix_sx ...
     696             : !> \param matrix_gx ...
     697             : !> \param qs_ot_env ...
     698             : ! **************************************************************************************************
     699        5992 :    SUBROUTINE qs_ot_get_derivative_ref(matrix_hc, matrix_x, matrix_sx, matrix_gx, &
     700             :                                        qs_ot_env)
     701             :       TYPE(dbcsr_type), POINTER                          :: matrix_hc, matrix_x, matrix_sx, matrix_gx
     702             :       TYPE(qs_ot_type)                                   :: qs_ot_env
     703             : 
     704             :       CHARACTER(len=*), PARAMETER :: routineN = 'qs_ot_get_derivative_ref'
     705             : 
     706             :       INTEGER                                            :: handle, k, n
     707             :       REAL(dp)                                           :: occ_in, occ_out
     708             :       TYPE(dbcsr_type), POINTER                          :: C, CHC, G, G_dp, HC, SC
     709             : 
     710        2996 :       CALL timeset(routineN, handle)
     711             : 
     712        2996 :       CALL dbcsr_get_info(matrix_x, nfullrows_total=n, nfullcols_total=k)
     713             :       !
     714        2996 :       C => matrix_x ! NBsf*NOcc
     715        2996 :       SC => matrix_sx ! NBsf*NOcc need to be up2date
     716        2996 :       HC => matrix_hc ! NBsf*NOcc
     717        2996 :       G => matrix_gx ! NBsf*NOcc
     718        2996 :       CHC => qs_ot_env%buf1_k_k_sym ! buffer
     719        2996 :       G_dp => qs_ot_env%buf1_n_k_dp ! buffer dp
     720             : 
     721             :       ! C'*(H*C)
     722        2996 :       CALL dbcsr_multiply('T', 'N', 1.0_dp, C, HC, 0.0_dp, CHC)
     723        2996 :       IF (qs_ot_env%settings%eps_irac_filter_matrix .GT. 0.0_dp) THEN
     724           4 :          occ_in = dbcsr_get_occupation(chc)
     725           4 :          CALL dbcsr_filter(chc, qs_ot_env%settings%eps_irac_filter_matrix)
     726           4 :          occ_out = dbcsr_get_occupation(chc)
     727             :       END IF
     728             :       ! (S*C)*(C'*H*C)
     729        2996 :       CALL dbcsr_multiply('N', 'N', 1.0_dp, SC, CHC, 0.0_dp, G)
     730        2996 :       IF (qs_ot_env%settings%eps_irac_filter_matrix .GT. 0.0_dp) THEN
     731           4 :          occ_in = dbcsr_get_occupation(g)
     732           4 :          CALL dbcsr_filter(g, qs_ot_env%settings%eps_irac_filter_matrix)
     733           4 :          occ_out = dbcsr_get_occupation(g)
     734             :       END IF
     735             :       ! G = 2*(1-S*C*C')*H*C
     736        2996 :       CALL dbcsr_add(G, HC, alpha_scalar=-1.0_dp, beta_scalar=1.0_dp)
     737             :       !
     738        2996 :       CALL timestop(handle)
     739        2996 :    END SUBROUTINE qs_ot_get_derivative_ref
     740             : 
     741             : ! **************************************************************************************************
     742             : !> \brief computes p=x*S*x and the matrix functionals related matrices
     743             : !> \param matrix_x ...
     744             : !> \param matrix_sx ...
     745             : !> \param qs_ot_env ...
     746             : ! **************************************************************************************************
     747      285519 :    SUBROUTINE qs_ot_get_p(matrix_x, matrix_sx, qs_ot_env)
     748             : 
     749             :       TYPE(dbcsr_type), POINTER                          :: matrix_x, matrix_sx
     750             :       TYPE(qs_ot_type)                                   :: qs_ot_env
     751             : 
     752             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'qs_ot_get_p'
     753             :       REAL(KIND=dp), PARAMETER                           :: rone = 1.0_dp, rzero = 0.0_dp
     754             : 
     755             :       INTEGER                                            :: handle, k, max_iter, n
     756             :       LOGICAL                                            :: converged
     757             :       REAL(KIND=dp)                                      :: max_ev, min_ev, threshold
     758             : 
     759       95173 :       CALL timeset(routineN, handle)
     760             : 
     761       95173 :       CALL dbcsr_get_info(matrix_x, nfullrows_total=n, nfullcols_total=k)
     762             : 
     763             :       ! get the overlap
     764             :       CALL dbcsr_multiply('T', 'N', rone, matrix_x, matrix_sx, rzero, &
     765       95173 :                           qs_ot_env%matrix_p)
     766             : 
     767             :       ! get an upper bound for the largest eigenvalue
     768             :       ! try using lancos first and fall back to gershgorin norm if it fails
     769       95173 :       max_iter = 30; threshold = 1.0E-03_dp
     770       95173 :       CALL arnoldi_extremal(qs_ot_env%matrix_p, max_ev, min_ev, converged, threshold, max_iter)
     771       95173 :       qs_ot_env%largest_eval_upper_bound = MAX(max_ev, ABS(min_ev))
     772             : 
     773       95173 :       IF (.NOT. converged) qs_ot_env%largest_eval_upper_bound = dbcsr_gershgorin_norm(qs_ot_env%matrix_p)
     774       95173 :       CALL decide_strategy(qs_ot_env)
     775       95173 :       IF (qs_ot_env%do_taylor) THEN
     776       51322 :          CALL qs_ot_p2m_taylor(qs_ot_env)
     777             :       ELSE
     778       43851 :          CALL qs_ot_p2m_diag(qs_ot_env)
     779             :       END IF
     780             : 
     781       95173 :       IF (qs_ot_env%settings%do_rotation) THEN
     782        3206 :          CALL qs_ot_generate_rotation(qs_ot_env)
     783             :       END IF
     784             : 
     785       95173 :       CALL timestop(handle)
     786             : 
     787       95173 :    END SUBROUTINE qs_ot_get_p
     788             : 
     789             : ! **************************************************************************************************
     790             : !> \brief computes the rotation matrix rot_mat_u that is associated to a given
     791             : !>        rot_mat_x using rot_mat_u=exp(rot_mat_x)
     792             : !> \param qs_ot_env a valid qs_ot_env
     793             : !> \par History
     794             : !>      08.2004 created [Joost VandeVondele]
     795             : !>      12.2024 Rewrite to use only real matrices [Ole Schuett]
     796             : ! **************************************************************************************************
     797        3206 :    SUBROUTINE qs_ot_generate_rotation(qs_ot_env)
     798             : 
     799             :       TYPE(qs_ot_type)                                   :: qs_ot_env
     800             : 
     801             :       CHARACTER(len=*), PARAMETER :: routineN = 'qs_ot_generate_rotation'
     802             : 
     803             :       INTEGER                                            :: handle, k
     804        3206 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: exp_evals_im, exp_evals_re
     805             :       TYPE(dbcsr_type)                                   :: buf_1, buf_2
     806             : 
     807        3206 :       CALL timeset(routineN, handle)
     808             : 
     809        3206 :       CALL dbcsr_get_info(qs_ot_env%rot_mat_x, nfullrows_total=k)
     810             : 
     811        3206 :       IF (k /= 0) THEN
     812             :          ! We want to compute: rot_mat_u = exp(i*rot_mat_x)
     813             : 
     814             :          ! Diagonalize: matrix = i*rot_mat_x.
     815             :          ! Note that matrix is imaginary and hermitian because rot_mat_x is real and anti-symmetric.
     816             :          CALL cp_dbcsr_heevd(matrix_im=qs_ot_env%rot_mat_x, &  ! matrix_re omitted because it's zero
     817             :                              eigenvectors_re=qs_ot_env%rot_mat_evec_re, &
     818             :                              eigenvectors_im=qs_ot_env%rot_mat_evec_im, &
     819             :                              eigenvalues=qs_ot_env%rot_mat_evals, &
     820             :                              para_env=qs_ot_env%para_env, &
     821        3154 :                              blacs_env=qs_ot_env%blacs_env)
     822             : 
     823             :          ! Compute: exp_evals = EXP(-i*rot_mat_evals)
     824       12616 :          ALLOCATE (exp_evals_re(k), exp_evals_im(k))
     825       16874 :          exp_evals_re(:) = COS(-qs_ot_env%rot_mat_evals(:))
     826       16874 :          exp_evals_im(:) = SIN(-qs_ot_env%rot_mat_evals(:))
     827             : 
     828             :          ! Compute: rot_mat_u = \sum_ij exp_evals_ij * |rot_mat_evec_i> <rot_mat_evec_j|
     829             :          ! Note that we need only two matrix multiplications because rot_mat_u is real.
     830        3154 :          CALL dbcsr_copy(buf_1, qs_ot_env%rot_mat_evec_re, name="buf_1")
     831        3154 :          CALL dbcsr_scale_by_vector(buf_1, alpha=exp_evals_re, side='right')
     832        3154 :          CALL dbcsr_copy(buf_2, qs_ot_env%rot_mat_evec_im, name="buf_2")
     833        3154 :          CALL dbcsr_scale_by_vector(buf_2, alpha=exp_evals_im, side='right')
     834        3154 :          CALL dbcsr_add(buf_1, buf_2, alpha_scalar=+1.0_dp, beta_scalar=-1.0_dp)
     835        3154 :          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)
     836             : 
     837        3154 :          CALL dbcsr_copy(buf_1, qs_ot_env%rot_mat_evec_im)
     838        3154 :          CALL dbcsr_scale_by_vector(buf_1, alpha=exp_evals_re, side='right')
     839        3154 :          CALL dbcsr_copy(buf_2, qs_ot_env%rot_mat_evec_re)
     840        3154 :          CALL dbcsr_scale_by_vector(buf_2, alpha=exp_evals_im, side='right')
     841        3154 :          CALL dbcsr_add(buf_1, buf_2, alpha_scalar=+1.0_dp, beta_scalar=+1.0_dp)
     842        3154 :          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)
     843             : 
     844             :          ! Clean up.
     845        3154 :          CALL dbcsr_release(buf_1)
     846        3154 :          CALL dbcsr_release(buf_2)
     847        3154 :          DEALLOCATE (exp_evals_re, exp_evals_im)
     848             :       END IF
     849             : 
     850        3206 :       CALL timestop(handle)
     851             : 
     852        6412 :    END SUBROUTINE qs_ot_generate_rotation
     853             : 
     854             : ! **************************************************************************************************
     855             : !> \brief computes the derivative fields with respect to rot_mat_x
     856             : !> \param qs_ot_env valid qs_ot_env. In particular qs_ot_generate_rotation has to be called before
     857             : !>                        and the rot_mat_dedu matrix has to be up to date
     858             : !> \par History
     859             : !>      08.2004 created [ Joost VandeVondele ]
     860             : !>      12.2024 Rewrite to use only real matrices [Ole Schuett]
     861             : ! **************************************************************************************************
     862        3244 :    SUBROUTINE qs_ot_rot_mat_derivative(qs_ot_env)
     863             :       TYPE(qs_ot_type)                         :: qs_ot_env
     864             : 
     865             :       CHARACTER(len=*), PARAMETER :: routineN = 'qs_ot_rot_mat_derivative'
     866             : 
     867             :       INTEGER                                  :: handle, i, j, k
     868             :       REAL(KIND=dp)                            :: e1, e2
     869             :       TYPE(dbcsr_type)                         :: outer_deriv_re, outer_deriv_im, mat_buf, &
     870             :                                                   inner_deriv_re, inner_deriv_im
     871             :       TYPE(dbcsr_iterator_type)                :: iter
     872        1622 :       INTEGER, DIMENSION(:), POINTER           :: row_blk_offset, col_blk_offset
     873        1622 :       REAL(dp), DIMENSION(:, :), POINTER       :: block_in_re, block_in_im, block_out_re, block_out_im
     874             :       INTEGER                                  :: row, col
     875             :       LOGICAL                                  :: found
     876             :       COMPLEX(dp)                              :: cval_in, cval_out
     877             :       TYPE(dbcsr_distribution_type)            :: dist
     878             : 
     879        1622 :       CALL timeset(routineN, handle)
     880             : 
     881        1622 :       CALL dbcsr_get_info(qs_ot_env%rot_mat_u, nfullrows_total=k)
     882        1622 :       IF (k /= 0) THEN
     883        1596 :          CALL dbcsr_copy(qs_ot_env%matrix_buf1, qs_ot_env%rot_mat_dedu)
     884             :          ! now we get to the derivative wrt the antisymmetric matrix rot_mat_x
     885        1596 :          CALL dbcsr_copy(mat_buf, qs_ot_env%rot_mat_dedu, "mat_buf")
     886             : 
     887             :          ! inner_deriv_ij = <rot_mat_evec_i| rot_mat_dedu |rot_mat_evec_j>
     888        1596 :          CALL dbcsr_copy(inner_deriv_re, qs_ot_env%rot_mat_dedu, "inner_deriv_re") ! TODO just create
     889        1596 :          CALL dbcsr_copy(inner_deriv_im, qs_ot_env%rot_mat_dedu, "inner_deriv_im") ! TODO just create
     890             : 
     891        1596 :          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)
     892        1596 :          CALL dbcsr_multiply('T', 'N', +1.0_dp, qs_ot_env%rot_mat_evec_im, mat_buf, 0.0_dp, inner_deriv_re)
     893        1596 :          CALL dbcsr_multiply('T', 'N', +1.0_dp, qs_ot_env%rot_mat_evec_re, mat_buf, 0.0_dp, inner_deriv_im)
     894             : 
     895        1596 :          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)
     896        1596 :          CALL dbcsr_multiply('T', 'N', +1.0_dp, qs_ot_env%rot_mat_evec_re, mat_buf, 1.0_dp, inner_deriv_re)
     897        1596 :          CALL dbcsr_multiply('T', 'N', -1.0_dp, qs_ot_env%rot_mat_evec_im, mat_buf, 1.0_dp, inner_deriv_im)
     898             : 
     899             :          ! outer_deriv_ij = cint(eval_i, eval_j) * inner_deriv_ij
     900        1596 :          CALL dbcsr_copy(outer_deriv_re, qs_ot_env%rot_mat_dedu, "outer_deriv_re") ! TODO just create
     901        1596 :          CALL dbcsr_copy(outer_deriv_im, qs_ot_env%rot_mat_dedu, "outer_deriv_im") ! TODO just create
     902             : 
     903        1596 :          CALL dbcsr_get_info(qs_ot_env%rot_mat_dedu, row_blk_offset=row_blk_offset, col_blk_offset=col_blk_offset)
     904        1596 :          CALL dbcsr_iterator_start(iter, qs_ot_env%rot_mat_dedu)
     905        2394 :          DO WHILE (dbcsr_iterator_blocks_left(iter))
     906         798 :             CALL dbcsr_iterator_next_block(iter, row, col)
     907         798 :             CALL dbcsr_get_block_p(inner_deriv_re, row, col, block_in_re, found)
     908         798 :             CALL dbcsr_get_block_p(inner_deriv_im, row, col, block_in_im, found)
     909         798 :             CALL dbcsr_get_block_p(outer_deriv_re, row, col, block_out_re, found)
     910         798 :             CALL dbcsr_get_block_p(outer_deriv_im, row, col, block_out_im, found)
     911             : 
     912        6011 :             DO i = 1, SIZE(block_in_re, 1)
     913       25610 :             DO j = 1, SIZE(block_in_re, 2)
     914       21195 :                e1 = qs_ot_env%rot_mat_evals(row_blk_offset(row) + i - 1)
     915       21195 :                e2 = qs_ot_env%rot_mat_evals(col_blk_offset(col) + j - 1)
     916       21195 :                cval_in = CMPLX(block_in_re(i, j), block_in_im(i, j), dp)
     917       21195 :                cval_out = cval_in*cint(e1, e2)
     918       21195 :                block_out_re(i, j) = REAL(cval_out)
     919       24812 :                block_out_im(i, j) = AIMAG(cval_out)
     920             :             END DO
     921             :             END DO
     922             :          END DO
     923        1596 :          CALL dbcsr_iterator_stop(iter)
     924        1596 :          CALL dbcsr_release(inner_deriv_re)
     925        1596 :          CALL dbcsr_release(inner_deriv_im)
     926             : 
     927             :          ! Compute: matrix_buf1 = \sum_i outer_deriv_ij * |rot_mat_evec_i> <rot_mat_evec_j|
     928        1596 :          CALL dbcsr_multiply('N', 'N', +1.0_dp, qs_ot_env%rot_mat_evec_re, outer_deriv_re, 0.0_dp, mat_buf)
     929        1596 :          CALL dbcsr_multiply('N', 'N', -1.0_dp, qs_ot_env%rot_mat_evec_im, outer_deriv_im, 1.0_dp, mat_buf)
     930        1596 :          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)
     931             : 
     932        1596 :          CALL dbcsr_multiply('N', 'N', +1.0_dp, qs_ot_env%rot_mat_evec_re, outer_deriv_im, 0.0_dp, mat_buf)
     933        1596 :          CALL dbcsr_multiply('N', 'N', +1.0_dp, qs_ot_env%rot_mat_evec_im, outer_deriv_re, 1.0_dp, mat_buf)
     934        1596 :          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)
     935             : 
     936             :          ! Account for anti-symmetry of rot_mat_x.
     937        1596 :          CALL dbcsr_get_info(qs_ot_env%matrix_buf3, distribution=dist)
     938             :          CALL dbcsr_transposed(qs_ot_env%matrix_buf2, qs_ot_env%matrix_buf1, &
     939             :                                shallow_data_copy=.FALSE., use_distribution=dist, &
     940        1596 :                                transpose_distribution=.FALSE.)
     941             : 
     942             :          ! rot_mat_gx = matrix_buf1^T - matrix_buf1
     943        1596 :          CALL dbcsr_add(qs_ot_env%matrix_buf1, qs_ot_env%matrix_buf2, alpha_scalar=-1.0_dp, beta_scalar=+1.0_dp)
     944        1596 :          CALL dbcsr_copy(qs_ot_env%rot_mat_gx, qs_ot_env%matrix_buf1)
     945             : 
     946        1596 :          CALL dbcsr_release(mat_buf)
     947        1596 :          CALL dbcsr_release(outer_deriv_re)
     948        1596 :          CALL dbcsr_release(outer_deriv_im)
     949             :       END IF
     950        3244 :       CALL timestop(handle)
     951             :    CONTAINS
     952             : 
     953             : ! **************************************************************************************************
     954             : !> \brief ...
     955             : !> \param e1 ...
     956             : !> \param e2 ...
     957             : !> \return ...
     958             : ! **************************************************************************************************
     959       21195 :       FUNCTION cint(e1, e2)
     960             :       REAL(KIND=dp)                                      :: e1, e2
     961             :       COMPLEX(KIND=dp)                                   :: cint
     962             : 
     963             :       COMPLEX(KIND=dp)                                   :: l1, l2, x
     964             :       INTEGER                                            :: I
     965             : 
     966       21195 :          l1 = (0.0_dp, -1.0_dp)*e1
     967       21195 :          l2 = (0.0_dp, -1.0_dp)*e2
     968       21195 :          IF (ABS(l1 - l2) .GT. 0.5_dp) THEN
     969         994 :             cint = (EXP(l1) - EXP(l2))/(l1 - l2)
     970             :          ELSE
     971             :             x = 1.0_dp
     972             :             cint = 0.0_dp
     973      343417 :             DO I = 1, 16
     974      323216 :                cint = cint + x
     975      343417 :                x = x*(l1 - l2)/REAL(I + 1, KIND=dp)
     976             :             END DO
     977       20201 :             cint = cint*EXP(l2)
     978             :          END IF
     979       21195 :       END FUNCTION cint
     980             :    END SUBROUTINE qs_ot_rot_mat_derivative
     981             : 
     982             : ! **************************************************************************************************
     983             : !> \brief decide strategy
     984             : !>        tries to decide if the taylor expansion of cos(sqrt(xsx)) converges rapidly enough
     985             : !>        to make a taylor expansion of the functions cos(sqrt(xsx)) and sin(sqrt(xsx))/sqrt(xsx)
     986             : !>        and their derivatives faster than their computation based on diagonalization since xsx can
     987             : !>        be very small, especially during dynamics, only a few terms might indeed be needed we find
     988             : !>        the necessary order N to have largest_eval_upper_bound**(N+1)/(2(N+1))! < eps_taylor
     989             : !> \param qs_ot_env ...
     990             : ! **************************************************************************************************
     991       95173 :    SUBROUTINE decide_strategy(qs_ot_env)
     992             :       TYPE(qs_ot_type)                                   :: qs_ot_env
     993             : 
     994             :       INTEGER                                            :: N
     995             :       REAL(KIND=dp)                                      :: num_error
     996             : 
     997       95173 :       qs_ot_env%do_taylor = .FALSE.
     998       95173 :       N = 0
     999       95173 :       num_error = qs_ot_env%largest_eval_upper_bound/(2.0_dp)
    1000      406173 :       DO WHILE (num_error > qs_ot_env%settings%eps_taylor .AND. N <= qs_ot_env%settings%max_taylor)
    1001      311000 :          N = N + 1
    1002      349999 :          num_error = num_error*qs_ot_env%largest_eval_upper_bound/REAL((2*N + 1)*(2*N + 2), KIND=dp)
    1003             :       END DO
    1004       95173 :       qs_ot_env%taylor_order = N
    1005       95173 :       IF (qs_ot_env%taylor_order <= qs_ot_env%settings%max_taylor) THEN
    1006       51322 :          qs_ot_env%do_taylor = .TRUE.
    1007             :       END IF
    1008             : 
    1009       95173 :    END SUBROUTINE decide_strategy
    1010             : 
    1011             : ! **************************************************************************************************
    1012             : !> \brief c=(c0*cos(p^0.5)+x*sin(p^0.5)*p^(-0.5)) x rot_mat_u
    1013             : !>        this assumes that x is already ortho to S*C0, and that p is x*S*x
    1014             : !>        rot_mat_u is an optional rotation matrix
    1015             : !> \param matrix_c ...
    1016             : !> \param matrix_x ...
    1017             : !> \param qs_ot_env ...
    1018             : ! **************************************************************************************************
    1019      176830 :    SUBROUTINE qs_ot_get_orbitals(matrix_c, matrix_x, qs_ot_env)
    1020             : 
    1021             :       TYPE(dbcsr_type), POINTER                          :: matrix_c, matrix_x
    1022             :       TYPE(qs_ot_type)                                   :: qs_ot_env
    1023             : 
    1024             :       CHARACTER(len=*), PARAMETER :: routineN = 'qs_ot_get_orbitals'
    1025             :       REAL(KIND=dp), PARAMETER                           :: rone = 1.0_dp, rzero = 0.0_dp
    1026             : 
    1027             :       INTEGER                                            :: handle, k, n
    1028             :       TYPE(dbcsr_type), POINTER                          :: matrix_kk
    1029             : 
    1030       88415 :       CALL timeset(routineN, handle)
    1031             : 
    1032       88415 :       CALL dbcsr_get_info(matrix_x, nfullrows_total=n, nfullcols_total=k)
    1033             : 
    1034             :       ! rotate the multiplying matrices cosp and sinp instead of the result,
    1035             :       ! this should be cheaper for large basis sets
    1036       88415 :       IF (qs_ot_env%settings%do_rotation) THEN
    1037        2996 :          matrix_kk => qs_ot_env%matrix_buf1
    1038             :          CALL dbcsr_multiply('N', 'N', rone, qs_ot_env%matrix_cosp, &
    1039        2996 :                              qs_ot_env%rot_mat_u, rzero, matrix_kk)
    1040             :       ELSE
    1041       85419 :          matrix_kk => qs_ot_env%matrix_cosp
    1042             :       END IF
    1043             : 
    1044             :       CALL dbcsr_multiply('N', 'N', rone, qs_ot_env%matrix_c0, matrix_kk, &
    1045       88415 :                           rzero, matrix_c)
    1046             : 
    1047       88415 :       IF (qs_ot_env%settings%do_rotation) THEN
    1048        2996 :          matrix_kk => qs_ot_env%matrix_buf1
    1049             :          CALL dbcsr_multiply('N', 'N', rone, qs_ot_env%matrix_sinp, &
    1050        2996 :                              qs_ot_env%rot_mat_u, rzero, matrix_kk)
    1051             :       ELSE
    1052       85419 :          matrix_kk => qs_ot_env%matrix_sinp
    1053             :       END IF
    1054             :       CALL dbcsr_multiply('N', 'N', rone, matrix_x, matrix_kk, &
    1055       88415 :                           rone, matrix_c)
    1056             : 
    1057       88415 :       CALL timestop(handle)
    1058             : 
    1059       88415 :    END SUBROUTINE qs_ot_get_orbitals
    1060             : 
    1061             : ! **************************************************************************************************
    1062             : !> \brief this routines computes dE/dx=dx, with dx ortho to sc0
    1063             : !>        needs dE/dC=hc,C0,X,SX,p
    1064             : !>        if preconditioned it will not be the derivative, but the lagrangian multiplier
    1065             : !>        is changed so that P*dE/dx is the right derivative (i.e. in the allowed subspace)
    1066             : !> \param matrix_hc ...
    1067             : !> \param matrix_x ...
    1068             : !> \param matrix_sx ...
    1069             : !> \param matrix_gx ...
    1070             : !> \param qs_ot_env ...
    1071             : ! **************************************************************************************************
    1072      198861 :    SUBROUTINE qs_ot_get_derivative(matrix_hc, matrix_x, matrix_sx, matrix_gx, &
    1073             :                                    qs_ot_env)
    1074             :       TYPE(dbcsr_type), POINTER                          :: matrix_hc, matrix_x, matrix_sx, matrix_gx
    1075             :       TYPE(qs_ot_type)                                   :: qs_ot_env
    1076             : 
    1077             :       CHARACTER(len=*), PARAMETER :: routineN = 'qs_ot_get_derivative'
    1078             :       REAL(KIND=dp), PARAMETER                           :: rone = 1.0_dp, rzero = 0.0_dp
    1079             : 
    1080             :       INTEGER                                            :: handle, k, n, ortho_k
    1081             :       TYPE(dbcsr_type), POINTER                          :: matrix_hc_local, matrix_target
    1082             : 
    1083       66287 :       CALL timeset(routineN, handle)
    1084             : 
    1085       66287 :       NULLIFY (matrix_hc_local)
    1086             : 
    1087       66287 :       CALL dbcsr_get_info(matrix_x, nfullrows_total=n, nfullcols_total=k)
    1088             : 
    1089             :       ! could in principle be taken inside qs_ot_get_derivative_* for increased efficiency
    1090             :       ! create a local rotated version of matrix_hc leaving matrix_hc untouched (needed
    1091             :       ! for lagrangian multipliers)
    1092       66287 :       IF (qs_ot_env%settings%do_rotation) THEN
    1093        1622 :          CALL dbcsr_copy(matrix_gx, matrix_hc) ! use gx as temporary
    1094        1622 :          CALL dbcsr_init_p(matrix_hc_local)
    1095        1622 :          CALL dbcsr_copy(matrix_hc_local, matrix_hc, name='matrix_hc_local')
    1096        1622 :          CALL dbcsr_set(matrix_hc_local, 0.0_dp)
    1097        1622 :          CALL dbcsr_multiply('N', 'T', rone, matrix_gx, qs_ot_env%rot_mat_u, rzero, matrix_hc_local)
    1098             :       ELSE
    1099       64665 :          matrix_hc_local => matrix_hc
    1100             :       END IF
    1101             : 
    1102       66287 :       IF (qs_ot_env%do_taylor) THEN
    1103       36981 :          CALL qs_ot_get_derivative_taylor(matrix_hc_local, matrix_x, matrix_sx, matrix_gx, qs_ot_env)
    1104             :       ELSE
    1105       29306 :          CALL qs_ot_get_derivative_diag(matrix_hc_local, matrix_x, matrix_sx, matrix_gx, qs_ot_env)
    1106             :       END IF
    1107             : 
    1108             :       ! and make it orthogonal
    1109       66287 :       CALL dbcsr_get_info(qs_ot_env%matrix_sc0, nfullcols_total=ortho_k)
    1110             : 
    1111       66287 :       IF (ASSOCIATED(qs_ot_env%preconditioner)) THEN
    1112       55467 :          matrix_target => qs_ot_env%matrix_psc0
    1113             :       ELSE
    1114       10820 :          matrix_target => qs_ot_env%matrix_sc0
    1115             :       END IF
    1116             :       ! first make the matrix os if not yet valid
    1117       66287 :       IF (.NOT. qs_ot_env%os_valid) THEN
    1118             :          ! this assumes that the preconditioner is a single matrix
    1119             :          ! that maps sc0 onto psc0
    1120             : 
    1121        7292 :          IF (ASSOCIATED(qs_ot_env%preconditioner)) THEN
    1122             :             CALL apply_preconditioner(qs_ot_env%preconditioner, qs_ot_env%matrix_sc0, &
    1123        6322 :                                       qs_ot_env%matrix_psc0)
    1124             :          END IF
    1125             :          CALL dbcsr_multiply('T', 'N', rone, &
    1126             :                              qs_ot_env%matrix_sc0, matrix_target, &
    1127        7292 :                              rzero, qs_ot_env%matrix_os)
    1128             :          CALL cp_dbcsr_cholesky_decompose(qs_ot_env%matrix_os, &
    1129        7292 :                                           para_env=qs_ot_env%para_env, blacs_env=qs_ot_env%blacs_env)
    1130             :          CALL cp_dbcsr_cholesky_invert(qs_ot_env%matrix_os, &
    1131             :                                        para_env=qs_ot_env%para_env, blacs_env=qs_ot_env%blacs_env, &
    1132        7292 :                                        uplo_to_full=.TRUE.)
    1133        7292 :          qs_ot_env%os_valid = .TRUE.
    1134             :       END IF
    1135             :       CALL dbcsr_multiply('T', 'N', rone, matrix_target, matrix_gx, &
    1136       66287 :                           rzero, qs_ot_env%matrix_buf1_ortho)
    1137             :       CALL dbcsr_multiply('N', 'N', rone, qs_ot_env%matrix_os, &
    1138       66287 :                           qs_ot_env%matrix_buf1_ortho, rzero, qs_ot_env%matrix_buf2_ortho)
    1139             :       CALL dbcsr_multiply('N', 'N', -rone, qs_ot_env%matrix_sc0, &
    1140       66287 :                           qs_ot_env%matrix_buf2_ortho, rone, matrix_gx)
    1141             :       ! also treat the rot_mat gradient here
    1142       66287 :       IF (qs_ot_env%settings%do_rotation) THEN
    1143        1622 :          CALL qs_ot_rot_mat_derivative(qs_ot_env)
    1144             :       END IF
    1145             : 
    1146       66287 :       IF (qs_ot_env%settings%do_rotation) THEN
    1147        1622 :          CALL dbcsr_release_p(matrix_hc_local)
    1148             :       END IF
    1149             : 
    1150       66287 :       CALL timestop(handle)
    1151             : 
    1152       66287 :    END SUBROUTINE qs_ot_get_derivative
    1153             : 
    1154             : ! **************************************************************************************************
    1155             : !> \brief ...
    1156             : !> \param matrix_hc ...
    1157             : !> \param matrix_x ...
    1158             : !> \param matrix_sx ...
    1159             : !> \param matrix_gx ...
    1160             : !> \param qs_ot_env ...
    1161             : ! **************************************************************************************************
    1162       87918 :    SUBROUTINE qs_ot_get_derivative_diag(matrix_hc, matrix_x, matrix_sx, matrix_gx, &
    1163             :                                         qs_ot_env)
    1164             : 
    1165             :       TYPE(dbcsr_type), POINTER                          :: matrix_hc, matrix_x, matrix_sx, matrix_gx
    1166             :       TYPE(qs_ot_type)                                   :: qs_ot_env
    1167             : 
    1168             :       CHARACTER(len=*), PARAMETER :: routineN = 'qs_ot_get_derivative_diag'
    1169             :       REAL(KIND=dp), PARAMETER                           :: rone = 1.0_dp, rzero = 0.0_dp
    1170             : 
    1171             :       INTEGER                                            :: handle, k, n
    1172             :       TYPE(dbcsr_distribution_type)                      :: dist
    1173             : 
    1174       29306 :       CALL timeset(routineN, handle)
    1175             : 
    1176       29306 :       CALL dbcsr_get_info(matrix_x, nfullrows_total=n, nfullcols_total=k)
    1177             : 
    1178             :       ! go for the derivative now
    1179             :       ! this de/dc*(dX/dx)*sinp
    1180       29306 :       CALL dbcsr_multiply('N', 'N', rone, matrix_hc, qs_ot_env%matrix_sinp, rzero, matrix_gx)
    1181             :       ! overlap hc*x
    1182       29306 :       CALL dbcsr_multiply('T', 'N', rone, matrix_hc, matrix_x, rzero, qs_ot_env%matrix_buf2)
    1183             :       ! get it in the basis of the eigenvectors
    1184             :       CALL dbcsr_multiply('N', 'N', rone, qs_ot_env%matrix_buf2, qs_ot_env%matrix_r, &
    1185       29306 :                           rzero, qs_ot_env%matrix_buf1)
    1186             :       CALL dbcsr_multiply('T', 'N', rone, qs_ot_env%matrix_r, qs_ot_env%matrix_buf1, &
    1187       29306 :                           rzero, qs_ot_env%matrix_buf2)
    1188             : 
    1189             :       ! get the schur product of O_uv*B_uv
    1190             :       CALL dbcsr_hadamard_product(qs_ot_env%matrix_buf2, qs_ot_env%matrix_sinp_b, &
    1191       29306 :                                   qs_ot_env%matrix_buf3)
    1192             : 
    1193             :       ! overlap hc*c0
    1194             :       CALL dbcsr_multiply('T', 'N', rone, matrix_hc, qs_ot_env%matrix_c0, rzero, &
    1195       29306 :                           qs_ot_env%matrix_buf2)
    1196             :       ! get it in the basis of the eigenvectors
    1197             :       CALL dbcsr_multiply('N', 'N', rone, qs_ot_env%matrix_buf2, qs_ot_env%matrix_r, &
    1198       29306 :                           rzero, qs_ot_env%matrix_buf1)
    1199             :       CALL dbcsr_multiply('T', 'N', rone, qs_ot_env%matrix_r, qs_ot_env%matrix_buf1, &
    1200       29306 :                           rzero, qs_ot_env%matrix_buf2)
    1201             : 
    1202             :       CALL dbcsr_hadamard_product(qs_ot_env%matrix_buf2, qs_ot_env%matrix_cosp_b, &
    1203       29306 :                                   qs_ot_env%matrix_buf4)
    1204             : 
    1205             :       ! add the two bs and compute b+b^T
    1206             :       CALL dbcsr_add(qs_ot_env%matrix_buf3, qs_ot_env%matrix_buf4, &
    1207       29306 :                      alpha_scalar=rone, beta_scalar=rone)
    1208             : 
    1209             :       ! get the b in the eigenvector basis
    1210             :       CALL dbcsr_multiply('N', 'T', rone, qs_ot_env%matrix_buf3, qs_ot_env%matrix_r, &
    1211       29306 :                           rzero, qs_ot_env%matrix_buf1)
    1212             :       CALL dbcsr_multiply('N', 'N', rone, qs_ot_env%matrix_r, qs_ot_env%matrix_buf1, &
    1213       29306 :                           rzero, qs_ot_env%matrix_buf3)
    1214       29306 :       CALL dbcsr_get_info(qs_ot_env%matrix_buf3, distribution=dist)
    1215             :       CALL dbcsr_transposed(qs_ot_env%matrix_buf1, qs_ot_env%matrix_buf3, &
    1216             :                             shallow_data_copy=.FALSE., use_distribution=dist, &
    1217       29306 :                             transpose_distribution=.FALSE.)
    1218             :       CALL dbcsr_add(qs_ot_env%matrix_buf3, qs_ot_env%matrix_buf1, &
    1219       29306 :                      alpha_scalar=rone, beta_scalar=rone)
    1220             : 
    1221             :       ! and add to the derivative
    1222             :       CALL dbcsr_multiply('N', 'N', rone, matrix_sx, qs_ot_env%matrix_buf3, &
    1223       29306 :                           rone, matrix_gx)
    1224       29306 :       CALL timestop(handle)
    1225             : 
    1226       29306 :    END SUBROUTINE qs_ot_get_derivative_diag
    1227             : 
    1228             : ! **************************************************************************************************
    1229             : !> \brief compute the derivative of the taylor expansion below
    1230             : !> \param matrix_hc ...
    1231             : !> \param matrix_x ...
    1232             : !> \param matrix_sx ...
    1233             : !> \param matrix_gx ...
    1234             : !> \param qs_ot_env ...
    1235             : ! **************************************************************************************************
    1236      132848 :    SUBROUTINE qs_ot_get_derivative_taylor(matrix_hc, matrix_x, matrix_sx, matrix_gx, &
    1237             :                                           qs_ot_env)
    1238             : 
    1239             :       TYPE(dbcsr_type), POINTER                          :: matrix_hc, matrix_x, matrix_sx, matrix_gx
    1240             :       TYPE(qs_ot_type)                                   :: qs_ot_env
    1241             : 
    1242             :       CHARACTER(len=*), PARAMETER :: routineN = 'qs_ot_get_derivative_taylor'
    1243             :       REAL(KIND=dp), PARAMETER                           :: rone = 1.0_dp, rzero = 0.0_dp
    1244             : 
    1245             :       INTEGER                                            :: handle, i, k, n
    1246             :       REAL(KIND=dp)                                      :: cosfactor, sinfactor
    1247             :       TYPE(dbcsr_distribution_type)                      :: dist
    1248             :       TYPE(dbcsr_type), POINTER                          :: matrix_left, matrix_right
    1249             : 
    1250       36981 :       CALL timeset(routineN, handle)
    1251             : 
    1252       36981 :       CALL dbcsr_get_info(matrix_x, nfullrows_total=n, nfullcols_total=k)
    1253             : 
    1254             :       ! go for the derivative now
    1255             :       ! this de/dc*(dX/dx)*sinp i.e. zeroth order
    1256       36981 :       CALL dbcsr_multiply('N', 'N', rone, matrix_hc, qs_ot_env%matrix_sinp, rzero, matrix_gx)
    1257             : 
    1258       36981 :       IF (qs_ot_env%taylor_order .LE. 0) THEN
    1259        7538 :          CALL timestop(handle)
    1260        7538 :          RETURN
    1261             :       END IF
    1262             : 
    1263             :       ! we store the matrix that will multiply sx in matrix_r
    1264       29443 :       CALL dbcsr_set(qs_ot_env%matrix_r, rzero)
    1265             : 
    1266             :       ! just better names for matrix_cosp_b and matrix_sinp_b (they are buffer space here)
    1267       29443 :       matrix_left => qs_ot_env%matrix_cosp_b
    1268       29443 :       matrix_right => qs_ot_env%matrix_sinp_b
    1269             : 
    1270             :       ! overlap hc*x and add its transpose to matrix_left
    1271       29443 :       CALL dbcsr_multiply('T', 'N', rone, matrix_hc, matrix_x, rzero, matrix_left)
    1272       29443 :       CALL dbcsr_get_info(matrix_left, distribution=dist)
    1273             :       CALL dbcsr_transposed(qs_ot_env%matrix_buf1, matrix_left, &
    1274             :                             shallow_data_copy=.FALSE., use_distribution=dist, &
    1275       29443 :                             transpose_distribution=.FALSE.)
    1276             :       CALL dbcsr_add(matrix_left, qs_ot_env%matrix_buf1, &
    1277       29443 :                      alpha_scalar=1.0_dp, beta_scalar=1.0_dp)
    1278       29443 :       CALL dbcsr_copy(matrix_right, matrix_left)
    1279             : 
    1280             :       ! first order
    1281       29443 :       sinfactor = -1.0_dp/(2.0_dp*3.0_dp)
    1282             :       CALL dbcsr_add(qs_ot_env%matrix_r, matrix_left, &
    1283       29443 :                      alpha_scalar=1.0_dp, beta_scalar=sinfactor)
    1284             : 
    1285             :       !      M
    1286             :       !    OM+MO
    1287             :       ! OOM+OMO+MOO
    1288             :       !   ...
    1289       62393 :       DO i = 2, qs_ot_env%taylor_order
    1290       32950 :          sinfactor = sinfactor*(-1.0_dp)/REAL(2*i*(2*i + 1), KIND=dp)
    1291       32950 :          CALL dbcsr_multiply('N', 'N', rone, qs_ot_env%matrix_p, matrix_left, rzero, qs_ot_env%matrix_buf1)
    1292       32950 :          CALL dbcsr_multiply('N', 'N', rone, matrix_right, qs_ot_env%matrix_p, rzero, matrix_left)
    1293       32950 :          CALL dbcsr_copy(matrix_right, matrix_left)
    1294             :          CALL dbcsr_add(matrix_left, qs_ot_env%matrix_buf1, &
    1295       32950 :                         1.0_dp, 1.0_dp)
    1296             :          CALL dbcsr_add(qs_ot_env%matrix_r, matrix_left, &
    1297       62393 :                         alpha_scalar=1.0_dp, beta_scalar=sinfactor)
    1298             :       END DO
    1299             : 
    1300             :       ! overlap hc*c0 and add its transpose to matrix_left
    1301       29443 :       CALL dbcsr_multiply('T', 'N', rone, matrix_hc, qs_ot_env%matrix_c0, rzero, matrix_left)
    1302       29443 :       CALL dbcsr_get_info(matrix_left, distribution=dist)
    1303             :       CALL dbcsr_transposed(qs_ot_env%matrix_buf1, matrix_left, &
    1304             :                             shallow_data_copy=.FALSE., use_distribution=dist, &
    1305       29443 :                             transpose_distribution=.FALSE.)
    1306       29443 :       CALL dbcsr_add(matrix_left, qs_ot_env%matrix_buf1, 1.0_dp, 1.0_dp)
    1307       29443 :       CALL dbcsr_copy(matrix_right, matrix_left)
    1308             : 
    1309             :       ! first order
    1310       29443 :       cosfactor = -1.0_dp/(1.0_dp*2.0_dp)
    1311             :       CALL dbcsr_add(qs_ot_env%matrix_r, matrix_left, &
    1312       29443 :                      alpha_scalar=1.0_dp, beta_scalar=cosfactor)
    1313             : 
    1314             :       !      M
    1315             :       !    OM+MO
    1316             :       ! OOM+OMO+MOO
    1317             :       !   ...
    1318       62393 :       DO i = 2, qs_ot_env%taylor_order
    1319       32950 :          cosfactor = cosfactor*(-1.0_dp)/REAL(2*i*(2*i - 1), KIND=dp)
    1320       32950 :          CALL dbcsr_multiply('N', 'N', rone, qs_ot_env%matrix_p, matrix_left, rzero, qs_ot_env%matrix_buf1)
    1321       32950 :          CALL dbcsr_multiply('N', 'N', rone, matrix_right, qs_ot_env%matrix_p, rzero, matrix_left)
    1322       32950 :          CALL dbcsr_copy(matrix_right, matrix_left)
    1323       32950 :          CALL dbcsr_add(matrix_left, qs_ot_env%matrix_buf1, 1.0_dp, 1.0_dp)
    1324             :          CALL dbcsr_add(qs_ot_env%matrix_r, matrix_left, &
    1325       62393 :                         alpha_scalar=1.0_dp, beta_scalar=cosfactor)
    1326             :       END DO
    1327             : 
    1328             :       ! and add to the derivative
    1329       29443 :       CALL dbcsr_multiply('N', 'N', rone, matrix_sx, qs_ot_env%matrix_r, rone, matrix_gx)
    1330             : 
    1331       29443 :       CALL timestop(handle)
    1332             : 
    1333       36981 :    END SUBROUTINE qs_ot_get_derivative_taylor
    1334             : 
    1335             : ! *************************************************************************************************
    1336             : !> \brief computes a taylor expansion.
    1337             : !> \param qs_ot_env ...
    1338             : ! **************************************************************************************************
    1339       83515 :    SUBROUTINE qs_ot_p2m_taylor(qs_ot_env)
    1340             :       TYPE(qs_ot_type)                                   :: qs_ot_env
    1341             : 
    1342             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'qs_ot_p2m_taylor'
    1343             :       REAL(KIND=dp), PARAMETER                           :: rone = 1.0_dp, rzero = 0.0_dp
    1344             : 
    1345             :       INTEGER                                            :: handle, i, k
    1346             :       REAL(KIND=dp)                                      :: cosfactor, sinfactor
    1347             : 
    1348       51322 :       CALL timeset(routineN, handle)
    1349             : 
    1350             :       ! zeroth order
    1351       51322 :       CALL dbcsr_set(qs_ot_env%matrix_cosp, rzero)
    1352       51322 :       CALL dbcsr_set(qs_ot_env%matrix_sinp, rzero)
    1353       51322 :       CALL dbcsr_add_on_diag(qs_ot_env%matrix_cosp, rone)
    1354       51322 :       CALL dbcsr_add_on_diag(qs_ot_env%matrix_sinp, rone)
    1355             : 
    1356       51322 :       IF (qs_ot_env%taylor_order .LE. 0) THEN
    1357        8112 :          CALL timestop(handle)
    1358       19129 :          RETURN
    1359             :       END IF
    1360             : 
    1361             :       ! first order
    1362       43210 :       cosfactor = -1.0_dp/(1.0_dp*2.0_dp)
    1363       43210 :       sinfactor = -1.0_dp/(2.0_dp*3.0_dp)
    1364       43210 :       CALL dbcsr_add(qs_ot_env%matrix_cosp, qs_ot_env%matrix_p, alpha_scalar=1.0_dp, beta_scalar=cosfactor)
    1365       43210 :       CALL dbcsr_add(qs_ot_env%matrix_sinp, qs_ot_env%matrix_p, alpha_scalar=1.0_dp, beta_scalar=sinfactor)
    1366       43210 :       IF (qs_ot_env%taylor_order .LE. 1) THEN
    1367       11017 :          CALL timestop(handle)
    1368       11017 :          RETURN
    1369             :       END IF
    1370             : 
    1371             :       ! other orders
    1372       32193 :       CALL dbcsr_get_info(qs_ot_env%matrix_p, nfullrows_total=k)
    1373       32193 :       CALL dbcsr_copy(qs_ot_env%matrix_r, qs_ot_env%matrix_p)
    1374             : 
    1375       80728 :       DO i = 2, qs_ot_env%taylor_order
    1376             :          ! new power of p
    1377             :          CALL dbcsr_multiply('N', 'N', rone, qs_ot_env%matrix_p, qs_ot_env%matrix_r, &
    1378       48535 :                              rzero, qs_ot_env%matrix_buf1)
    1379       48535 :          CALL dbcsr_copy(qs_ot_env%matrix_r, qs_ot_env%matrix_buf1)
    1380             :          ! add to the taylor expansion so far
    1381       48535 :          cosfactor = cosfactor*(-1.0_dp)/REAL(2*i*(2*i - 1), KIND=dp)
    1382       48535 :          sinfactor = sinfactor*(-1.0_dp)/REAL(2*i*(2*i + 1), KIND=dp)
    1383             :          CALL dbcsr_add(qs_ot_env%matrix_cosp, qs_ot_env%matrix_r, &
    1384       48535 :                         alpha_scalar=1.0_dp, beta_scalar=cosfactor)
    1385             :          CALL dbcsr_add(qs_ot_env%matrix_sinp, qs_ot_env%matrix_r, &
    1386       80728 :                         alpha_scalar=1.0_dp, beta_scalar=sinfactor)
    1387             :       END DO
    1388             : 
    1389       32193 :       CALL timestop(handle)
    1390             : 
    1391             :    END SUBROUTINE qs_ot_p2m_taylor
    1392             : 
    1393             : ! **************************************************************************************************
    1394             : !> \brief given p, computes  - eigenstuff (matrix_r,evals)
    1395             : !>        - cos(p^0.5),p^(-0.5)*sin(p^0.5)
    1396             : !>        - the real b matrices, needed for the derivatives of these guys
    1397             : !>        cosp_b_ij=(1/(2pii) * int(cos(z^1/2)/((z-eval(i))*(z-eval(j))))
    1398             : !>        sinp_b_ij=(1/(2pii) * int(z^(-1/2)*sin(z^1/2)/((z-eval(i))*(z-eval(j))))
    1399             : !> \param qs_ot_env ...
    1400             : ! **************************************************************************************************
    1401      175404 :    SUBROUTINE qs_ot_p2m_diag(qs_ot_env)
    1402             : 
    1403             :       TYPE(qs_ot_type)                                   :: qs_ot_env
    1404             : 
    1405             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'qs_ot_p2m_diag'
    1406             :       REAL(KIND=dp), PARAMETER                           :: rone = 1.0_dp, rzero = 0.0_dp
    1407             : 
    1408             :       INTEGER                                            :: col, col_offset, col_size, handle, i, j, &
    1409             :                                                             k, row, row_offset, row_size
    1410       43851 :       REAL(dp), DIMENSION(:, :), POINTER                 :: block
    1411             :       REAL(KIND=dp)                                      :: a, b
    1412             :       TYPE(dbcsr_iterator_type)                          :: iter
    1413             : 
    1414       43851 :       CALL timeset(routineN, handle)
    1415             : 
    1416       43851 :       CALL dbcsr_get_info(qs_ot_env%matrix_p, nfullrows_total=k)
    1417       43851 :       CALL dbcsr_copy(qs_ot_env%matrix_buf1, qs_ot_env%matrix_p)
    1418             :       CALL cp_dbcsr_syevd(qs_ot_env%matrix_buf1, qs_ot_env%matrix_r, qs_ot_env%evals, &
    1419       43851 :                           qs_ot_env%para_env, qs_ot_env%blacs_env)
    1420      497724 :       DO i = 1, k
    1421      497724 :          qs_ot_env%evals(i) = MAX(0.0_dp, qs_ot_env%evals(i))
    1422             :       END DO
    1423             : 
    1424       43851 :       !$OMP PARALLEL DO DEFAULT(NONE) PRIVATE(i) SHARED(k,qs_ot_env)
    1425             :       DO i = 1, k
    1426             :          qs_ot_env%dum(i) = COS(SQRT(qs_ot_env%evals(i)))
    1427             :       END DO
    1428       43851 :       CALL dbcsr_copy(qs_ot_env%matrix_buf1, qs_ot_env%matrix_r)
    1429       43851 :       CALL dbcsr_scale_by_vector(qs_ot_env%matrix_buf1, alpha=qs_ot_env%dum, side='right')
    1430             :       CALL dbcsr_multiply('N', 'T', rone, qs_ot_env%matrix_r, qs_ot_env%matrix_buf1, &
    1431       43851 :                           rzero, qs_ot_env%matrix_cosp)
    1432             : 
    1433       43851 :       !$OMP PARALLEL DO DEFAULT(NONE) PRIVATE(i) SHARED(k,qs_ot_env)
    1434             :       DO i = 1, k
    1435             :          qs_ot_env%dum(i) = qs_ot_sinc(SQRT(qs_ot_env%evals(i)))
    1436             :       END DO
    1437       43851 :       CALL dbcsr_copy(qs_ot_env%matrix_buf1, qs_ot_env%matrix_r)
    1438       43851 :       CALL dbcsr_scale_by_vector(qs_ot_env%matrix_buf1, alpha=qs_ot_env%dum, side='right')
    1439             :       CALL dbcsr_multiply('N', 'T', rone, qs_ot_env%matrix_r, qs_ot_env%matrix_buf1, &
    1440       43851 :                           rzero, qs_ot_env%matrix_sinp)
    1441             : 
    1442       43851 :       CALL dbcsr_copy(qs_ot_env%matrix_cosp_b, qs_ot_env%matrix_cosp)
    1443       43851 :       CALL dbcsr_iterator_start(iter, qs_ot_env%matrix_cosp_b)
    1444       77268 :       DO WHILE (dbcsr_iterator_blocks_left(iter))
    1445             :          CALL dbcsr_iterator_next_block(iter, row, col, block, &
    1446             :                                         row_size=row_size, col_size=col_size, &
    1447       33417 :                                         row_offset=row_offset, col_offset=col_offset)
    1448      540149 :          DO j = 1, col_size
    1449    10982964 :          DO i = 1, row_size
    1450             :             a = (SQRT(qs_ot_env%evals(row_offset + i - 1)) &
    1451    10486666 :                  - SQRT(qs_ot_env%evals(col_offset + j - 1)))/2.0_dp
    1452             :             b = (SQRT(qs_ot_env%evals(row_offset + i - 1)) &
    1453    10486666 :                  + SQRT(qs_ot_env%evals(col_offset + j - 1)))/2.0_dp
    1454    10949547 :             block(i, j) = -0.5_dp*qs_ot_sinc(a)*qs_ot_sinc(b)
    1455             :          END DO
    1456             :          END DO
    1457             :       END DO
    1458       43851 :       CALL dbcsr_iterator_stop(iter)
    1459             : 
    1460       43851 :       CALL dbcsr_copy(qs_ot_env%matrix_sinp_b, qs_ot_env%matrix_sinp)
    1461       43851 :       CALL dbcsr_iterator_start(iter, qs_ot_env%matrix_sinp_b)
    1462       77268 :       DO WHILE (dbcsr_iterator_blocks_left(iter))
    1463             :          CALL dbcsr_iterator_next_block(iter, row, col, block, &
    1464             :                                         row_size=row_size, col_size=col_size, &
    1465       33417 :                                         row_offset=row_offset, col_offset=col_offset)
    1466      540149 :          DO j = 1, col_size
    1467    10982964 :          DO i = 1, row_size
    1468    10486666 :             a = SQRT(qs_ot_env%evals(row_offset + i - 1))
    1469    10486666 :             b = SQRT(qs_ot_env%evals(col_offset + j - 1))
    1470    10949547 :             block(i, j) = qs_ot_sincf(a, b)
    1471             :          END DO
    1472             :          END DO
    1473             :       END DO
    1474       43851 :       CALL dbcsr_iterator_stop(iter)
    1475             : 
    1476       43851 :       CALL timestop(handle)
    1477             : 
    1478       43851 :    END SUBROUTINE qs_ot_p2m_diag
    1479             : 
    1480             : ! **************************************************************************************************
    1481             : !> \brief computes sin(x)/x for all values of the argument
    1482             : !> \param x ...
    1483             : !> \return ...
    1484             : ! **************************************************************************************************
    1485    29108633 :    FUNCTION qs_ot_sinc(x)
    1486             : 
    1487             :       REAL(KIND=dp), INTENT(IN)                          :: x
    1488             :       REAL(KIND=dp)                                      :: qs_ot_sinc
    1489             : 
    1490             :       REAL(KIND=dp), PARAMETER :: q1 = 1.0_dp, q2 = -q1/(2.0_dp*3.0_dp), q3 = -q2/(4.0_dp*5.0_dp), &
    1491             :          q4 = -q3/(6.0_dp*7.0_dp), q5 = -q4/(8.0_dp*9.0_dp), q6 = -q5/(10.0_dp*11.0_dp), &
    1492             :          q7 = -q6/(12.0_dp*13.0_dp), q8 = -q7/(14.0_dp*15.0_dp), q9 = -q8/(16.0_dp*17.0_dp), &
    1493             :          q10 = -q9/(18.0_dp*19.0_dp)
    1494             : 
    1495             :       REAL(KIND=dp)                                      :: y
    1496             : 
    1497    29108633 :       IF (ABS(x) > 0.5_dp) THEN
    1498     8621955 :          qs_ot_sinc = SIN(x)/x
    1499             :       ELSE
    1500    20486678 :          y = x*x
    1501    20486678 :          qs_ot_sinc = q1 + y*(q2 + y*(q3 + y*(q4 + y*(q5 + y*(q6 + y*(q7 + y*(q8 + y*(q9 + y*(q10)))))))))
    1502             :       END IF
    1503    29108633 :    END FUNCTION qs_ot_sinc
    1504             : 
    1505             : ! **************************************************************************************************
    1506             : !> \brief computes (1/(x^2-y^2))*(sinc(x)-sinc(y)) for all positive values of the arguments
    1507             : !> \param xa ...
    1508             : !> \param ya ...
    1509             : !> \return ...
    1510             : ! **************************************************************************************************
    1511    10486666 :    FUNCTION qs_ot_sincf(xa, ya)
    1512             : 
    1513             :       REAL(KIND=dp), INTENT(IN)                          :: xa, ya
    1514             :       REAL(KIND=dp)                                      :: qs_ot_sincf
    1515             : 
    1516             :       INTEGER                                            :: i
    1517             :       REAL(KIND=dp)                                      :: a, b, rs, sf, x, xs, y, ybx, ybxs
    1518             : 
    1519             :       ! this is currently a limit of the routine, could be removed rather easily
    1520    10486666 :       IF (xa .LT. 0) CPABORT("x is negative")
    1521    10486666 :       IF (ya .LT. 0) CPABORT("y is negative")
    1522             : 
    1523    10486666 :       IF (xa .LT. ya) THEN
    1524     5037246 :          x = ya
    1525     5037246 :          y = xa
    1526             :       ELSE
    1527     5449420 :          x = xa
    1528     5449420 :          y = ya
    1529             :       END IF
    1530             : 
    1531    10486666 :       IF (x .LT. 0.5_dp) THEN ! use series, keeping in mind that x,y,x+y,x-y can all be zero
    1532             : 
    1533     6645952 :          qs_ot_sincf = 0.0_dp
    1534     6645952 :          IF (x .GT. 0.0_dp) THEN
    1535     6444817 :             ybx = y/x
    1536             :          ELSE ! should be irrelevant  !?
    1537             :             ybx = 0.0_dp
    1538             :          END IF
    1539             : 
    1540     6645952 :          sf = -1.0_dp/((1.0_dp + ybx)*6.0_dp)
    1541     6645952 :          rs = 1.0_dp
    1542     6645952 :          ybxs = ybx
    1543     6645952 :          xs = 1.0_dp
    1544             : 
    1545    73105472 :          DO i = 1, 10
    1546    66459520 :             qs_ot_sincf = qs_ot_sincf + sf*rs*xs*(1.0_dp + ybxs)
    1547    66459520 :             sf = -sf/(REAL((2*i + 2), dp)*REAL((2*i + 3), dp))
    1548    66459520 :             rs = rs + ybxs
    1549    66459520 :             ybxs = ybxs*ybx
    1550    73105472 :             xs = xs*x*x
    1551             :          END DO
    1552             : 
    1553             :       ELSE ! no series expansion
    1554     3840714 :          IF (x - y .GT. 0.1_dp) THEN ! safe to use the normal form
    1555     3558524 :             qs_ot_sincf = (qs_ot_sinc(x) - qs_ot_sinc(y))/((x + y)*(x - y))
    1556             :          ELSE
    1557      282190 :             a = (x + y)/2.0_dp
    1558      282190 :             b = (x - y)/2.0_dp ! might be close to zero
    1559             :             ! y (=(a-b)) can not be close to zero since it is close to x>0.5
    1560      282190 :             qs_ot_sincf = (qs_ot_sinc(b)*COS(a) - qs_ot_sinc(a)*COS(b))/(2*x*y)
    1561             :          END IF
    1562             :       END IF
    1563             : 
    1564    10486666 :    END FUNCTION qs_ot_sincf
    1565             : 
    1566             : END MODULE qs_ot

Generated by: LCOV version 1.15