LCOV - code coverage report
Current view: top level - src - dm_ls_scf_methods.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:2fce0f8) Lines: 502 540 93.0 %
Date: 2024-12-21 06:28:57 Functions: 11 11 100.0 %

          Line data    Source code
       1             : !--------------------------------------------------------------------------------------------------!
       2             : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3             : !   Copyright 2000-2024 CP2K developers group <https://cp2k.org>                                   !
       4             : !                                                                                                  !
       5             : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6             : !--------------------------------------------------------------------------------------------------!
       7             : 
       8             : ! **************************************************************************************************
       9             : !> \brief lower level routines for linear scaling SCF
      10             : !> \par History
      11             : !>       2010.10 created [Joost VandeVondele]
      12             : !> \author Joost VandeVondele
      13             : ! **************************************************************************************************
      14             : MODULE dm_ls_scf_methods
      15             :    USE arnoldi_api,                     ONLY: arnoldi_extremal
      16             :    USE cp_dbcsr_api,                    ONLY: &
      17             :         dbcsr_add, dbcsr_add_on_diag, dbcsr_copy, dbcsr_create, dbcsr_desymmetrize, dbcsr_dot, &
      18             :         dbcsr_filter, dbcsr_finalize, dbcsr_frobenius_norm, dbcsr_get_data_type, &
      19             :         dbcsr_get_occupation, dbcsr_iterator_blocks_left, dbcsr_iterator_next_block, &
      20             :         dbcsr_iterator_start, dbcsr_iterator_stop, dbcsr_iterator_type, dbcsr_multiply, &
      21             :         dbcsr_put_block, dbcsr_release, dbcsr_scale, dbcsr_set, dbcsr_trace, dbcsr_type, &
      22             :         dbcsr_type_no_symmetry
      23             :    USE cp_log_handling,                 ONLY: cp_get_default_logger,&
      24             :                                               cp_logger_get_default_unit_nr,&
      25             :                                               cp_logger_type
      26             :    USE dm_ls_scf_qs,                    ONLY: matrix_qs_to_ls
      27             :    USE dm_ls_scf_types,                 ONLY: ls_cluster_atomic,&
      28             :                                               ls_mstruct_type,&
      29             :                                               ls_scf_env_type
      30             :    USE input_constants,                 ONLY: &
      31             :         ls_cluster_atomic, ls_s_preconditioner_atomic, ls_s_preconditioner_molecular, &
      32             :         ls_s_preconditioner_none, ls_s_sqrt_ns, ls_s_sqrt_proot, ls_scf_sign_ns, &
      33             :         ls_scf_sign_proot, ls_scf_sign_submatrix, ls_scf_submatrix_sign_direct_muadj, &
      34             :         ls_scf_submatrix_sign_direct_muadj_lowmem, ls_scf_submatrix_sign_ns
      35             :    USE iterate_matrix,                  ONLY: invert_Hotelling,&
      36             :                                               matrix_sign_Newton_Schulz,&
      37             :                                               matrix_sign_proot,&
      38             :                                               matrix_sign_submatrix,&
      39             :                                               matrix_sign_submatrix_mu_adjust,&
      40             :                                               matrix_sqrt_Newton_Schulz,&
      41             :                                               matrix_sqrt_proot
      42             :    USE kinds,                           ONLY: dp,&
      43             :                                               int_8
      44             :    USE machine,                         ONLY: m_flush,&
      45             :                                               m_walltime
      46             :    USE mathlib,                         ONLY: abnormal_value
      47             : #include "./base/base_uses.f90"
      48             : 
      49             :    IMPLICIT NONE
      50             : 
      51             :    PRIVATE
      52             : 
      53             :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'dm_ls_scf_methods'
      54             : 
      55             :    PUBLIC :: ls_scf_init_matrix_S
      56             :    PUBLIC :: density_matrix_sign, density_matrix_sign_fixed_mu
      57             :    PUBLIC :: apply_matrix_preconditioner, compute_matrix_preconditioner
      58             :    PUBLIC :: density_matrix_trs4, density_matrix_tc2, compute_homo_lumo
      59             : 
      60             : CONTAINS
      61             : 
      62             : ! **************************************************************************************************
      63             : !> \brief initialize S matrix related properties (sqrt, inverse...)
      64             : !>        Might be factored-out since this seems common code with the other SCF.
      65             : !> \param matrix_s ...
      66             : !> \param ls_scf_env ...
      67             : !> \par History
      68             : !>       2010.10 created [Joost VandeVondele]
      69             : !> \author Joost VandeVondele
      70             : ! **************************************************************************************************
      71       12730 :    SUBROUTINE ls_scf_init_matrix_S(matrix_s, ls_scf_env)
      72             :       TYPE(dbcsr_type)                                   :: matrix_s
      73             :       TYPE(ls_scf_env_type)                              :: ls_scf_env
      74             : 
      75             :       CHARACTER(len=*), PARAMETER :: routineN = 'ls_scf_init_matrix_S'
      76             : 
      77             :       INTEGER                                            :: handle, unit_nr
      78             :       REAL(KIND=dp)                                      :: frob_matrix, frob_matrix_base
      79             :       TYPE(cp_logger_type), POINTER                      :: logger
      80             :       TYPE(dbcsr_type)                                   :: matrix_tmp1, matrix_tmp2
      81             : 
      82       12730 :       CALL timeset(routineN, handle)
      83             : 
      84             :       ! get a useful output_unit
      85       12730 :       logger => cp_get_default_logger()
      86       12730 :       IF (logger%para_env%is_source()) THEN
      87        6365 :          unit_nr = cp_logger_get_default_unit_nr(logger, local=.TRUE.)
      88             :       ELSE
      89             :          unit_nr = -1
      90             :       END IF
      91             : 
      92             :       ! make our own copy of S
      93       12730 :       IF (ls_scf_env%has_unit_metric) THEN
      94          14 :          CALL dbcsr_set(ls_scf_env%matrix_s, 0.0_dp)
      95          14 :          CALL dbcsr_add_on_diag(ls_scf_env%matrix_s, 1.0_dp)
      96             :       ELSE
      97       12716 :          CALL matrix_qs_to_ls(ls_scf_env%matrix_s, matrix_s, ls_scf_env%ls_mstruct, covariant=.TRUE.)
      98             :       END IF
      99             : 
     100       12730 :       CALL dbcsr_filter(ls_scf_env%matrix_s, ls_scf_env%eps_filter)
     101             : 
     102             :       ! needs a preconditioner for S
     103       12730 :       IF (ls_scf_env%has_s_preconditioner) THEN
     104             :          CALL dbcsr_create(ls_scf_env%matrix_bs_sqrt, template=ls_scf_env%matrix_s, &
     105         356 :                            matrix_type=dbcsr_type_no_symmetry)
     106             :          CALL dbcsr_create(ls_scf_env%matrix_bs_sqrt_inv, template=ls_scf_env%matrix_s, &
     107         356 :                            matrix_type=dbcsr_type_no_symmetry)
     108             :          CALL compute_matrix_preconditioner(ls_scf_env%matrix_s, &
     109             :                                             ls_scf_env%s_preconditioner_type, ls_scf_env%ls_mstruct, &
     110             :                                             ls_scf_env%matrix_bs_sqrt, ls_scf_env%matrix_bs_sqrt_inv, &
     111             :                                             ls_scf_env%eps_filter, ls_scf_env%s_sqrt_order, &
     112         356 :                                             ls_scf_env%eps_lanczos, ls_scf_env%max_iter_lanczos)
     113             :       END IF
     114             : 
     115             :       ! precondition S
     116       12730 :       IF (ls_scf_env%has_s_preconditioner) THEN
     117             :          CALL apply_matrix_preconditioner(ls_scf_env%matrix_s, "forward", &
     118         356 :                                           ls_scf_env%matrix_bs_sqrt, ls_scf_env%matrix_bs_sqrt_inv)
     119             :       END IF
     120             : 
     121             :       ! compute sqrt(S) and inv(sqrt(S))
     122       12730 :       IF (ls_scf_env%use_s_sqrt) THEN
     123             : 
     124             :          CALL dbcsr_create(ls_scf_env%matrix_s_sqrt, template=ls_scf_env%matrix_s, &
     125       12712 :                            matrix_type=dbcsr_type_no_symmetry)
     126             :          CALL dbcsr_create(ls_scf_env%matrix_s_sqrt_inv, template=ls_scf_env%matrix_s, &
     127       12712 :                            matrix_type=dbcsr_type_no_symmetry)
     128             : 
     129       12720 :          SELECT CASE (ls_scf_env%s_sqrt_method)
     130             :          CASE (ls_s_sqrt_proot)
     131             :             CALL matrix_sqrt_proot(ls_scf_env%matrix_s_sqrt, ls_scf_env%matrix_s_sqrt_inv, &
     132             :                                    ls_scf_env%matrix_s, ls_scf_env%eps_filter, &
     133             :                                    ls_scf_env%s_sqrt_order, &
     134             :                                    ls_scf_env%eps_lanczos, ls_scf_env%max_iter_lanczos, &
     135           8 :                                    symmetrize=.TRUE.)
     136             :          CASE (ls_s_sqrt_ns)
     137             :             CALL matrix_sqrt_Newton_Schulz(ls_scf_env%matrix_s_sqrt, ls_scf_env%matrix_s_sqrt_inv, &
     138             :                                            ls_scf_env%matrix_s, ls_scf_env%eps_filter, &
     139             :                                            ls_scf_env%s_sqrt_order, &
     140             :                                            ls_scf_env%eps_lanczos, ls_scf_env%max_iter_lanczos, &
     141       12704 :                                            iounit=-1)
     142             :          CASE DEFAULT
     143       12712 :             CPABORT("Unknown sqrt method.")
     144             :          END SELECT
     145             : 
     146       12712 :          IF (ls_scf_env%check_s_inv) THEN
     147             :             CALL dbcsr_create(matrix_tmp1, template=ls_scf_env%matrix_s, &
     148           0 :                               matrix_type=dbcsr_type_no_symmetry)
     149             :             CALL dbcsr_create(matrix_tmp2, template=ls_scf_env%matrix_s, &
     150           0 :                               matrix_type=dbcsr_type_no_symmetry)
     151             : 
     152             :             CALL dbcsr_multiply("N", "N", 1.0_dp, ls_scf_env%matrix_s_sqrt_inv, ls_scf_env%matrix_s, &
     153           0 :                                 0.0_dp, matrix_tmp1, filter_eps=ls_scf_env%eps_filter)
     154             : 
     155             :             CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_tmp1, ls_scf_env%matrix_s_sqrt_inv, &
     156           0 :                                 0.0_dp, matrix_tmp2, filter_eps=ls_scf_env%eps_filter)
     157             : 
     158           0 :             frob_matrix_base = dbcsr_frobenius_norm(matrix_tmp2)
     159           0 :             CALL dbcsr_add_on_diag(matrix_tmp2, -1.0_dp)
     160           0 :             frob_matrix = dbcsr_frobenius_norm(matrix_tmp2)
     161           0 :             IF (unit_nr > 0) THEN
     162           0 :                WRITE (unit_nr, *) "Error for (inv(sqrt(S))*S*inv(sqrt(S))-I)", frob_matrix/frob_matrix_base
     163             :             END IF
     164             : 
     165           0 :             CALL dbcsr_release(matrix_tmp1)
     166           0 :             CALL dbcsr_release(matrix_tmp2)
     167             :          END IF
     168             :       END IF
     169             : 
     170             :       ! compute the inverse of S
     171       12730 :       IF (ls_scf_env%needs_s_inv) THEN
     172             :          CALL dbcsr_create(ls_scf_env%matrix_s_inv, template=ls_scf_env%matrix_s, &
     173       12686 :                            matrix_type=dbcsr_type_no_symmetry)
     174       12686 :          IF (.NOT. ls_scf_env%use_s_sqrt) THEN
     175           2 :             CALL invert_Hotelling(ls_scf_env%matrix_s_inv, ls_scf_env%matrix_s, ls_scf_env%eps_filter)
     176             :          ELSE
     177             :             CALL dbcsr_multiply("N", "N", 1.0_dp, ls_scf_env%matrix_s_sqrt_inv, ls_scf_env%matrix_s_sqrt_inv, &
     178       12684 :                                 0.0_dp, ls_scf_env%matrix_s_inv, filter_eps=ls_scf_env%eps_filter)
     179             :          END IF
     180       12686 :          IF (ls_scf_env%check_s_inv) THEN
     181             :             CALL dbcsr_create(matrix_tmp1, template=ls_scf_env%matrix_s, &
     182           0 :                               matrix_type=dbcsr_type_no_symmetry)
     183             :             CALL dbcsr_multiply("N", "N", 1.0_dp, ls_scf_env%matrix_s_inv, ls_scf_env%matrix_s, &
     184           0 :                                 0.0_dp, matrix_tmp1, filter_eps=ls_scf_env%eps_filter)
     185           0 :             frob_matrix_base = dbcsr_frobenius_norm(matrix_tmp1)
     186           0 :             CALL dbcsr_add_on_diag(matrix_tmp1, -1.0_dp)
     187           0 :             frob_matrix = dbcsr_frobenius_norm(matrix_tmp1)
     188           0 :             IF (unit_nr > 0) THEN
     189           0 :                WRITE (unit_nr, *) "Error for (inv(S)*S-I)", frob_matrix/frob_matrix_base
     190             :             END IF
     191           0 :             CALL dbcsr_release(matrix_tmp1)
     192             :          END IF
     193             :       END IF
     194             : 
     195       12730 :       CALL timestop(handle)
     196       12730 :    END SUBROUTINE ls_scf_init_matrix_s
     197             : 
     198             : ! **************************************************************************************************
     199             : !> \brief compute for a block positive definite matrix s (bs)
     200             : !>        the sqrt(bs) and inv(sqrt(bs))
     201             : !> \param matrix_s ...
     202             : !> \param preconditioner_type ...
     203             : !> \param ls_mstruct ...
     204             : !> \param matrix_bs_sqrt ...
     205             : !> \param matrix_bs_sqrt_inv ...
     206             : !> \param threshold ...
     207             : !> \param order ...
     208             : !> \param eps_lanczos ...
     209             : !> \param max_iter_lanczos ...
     210             : !> \par History
     211             : !>       2010.10 created [Joost VandeVondele]
     212             : !> \author Joost VandeVondele
     213             : ! **************************************************************************************************
     214         356 :    SUBROUTINE compute_matrix_preconditioner(matrix_s, preconditioner_type, ls_mstruct, &
     215             :                                             matrix_bs_sqrt, matrix_bs_sqrt_inv, threshold, order, &
     216             :                                             eps_lanczos, max_iter_lanczos)
     217             : 
     218             :       TYPE(dbcsr_type), INTENT(INOUT)                    :: matrix_s
     219             :       INTEGER                                            :: preconditioner_type
     220             :       TYPE(ls_mstruct_type)                              :: ls_mstruct
     221             :       TYPE(dbcsr_type), INTENT(INOUT)                    :: matrix_bs_sqrt, matrix_bs_sqrt_inv
     222             :       REAL(KIND=dp)                                      :: threshold
     223             :       INTEGER                                            :: order
     224             :       REAL(KIND=dp)                                      :: eps_lanczos
     225             :       INTEGER                                            :: max_iter_lanczos
     226             : 
     227             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'compute_matrix_preconditioner'
     228             : 
     229             :       INTEGER                                            :: datatype, handle, iblock_col, iblock_row
     230             :       LOGICAL                                            :: block_needed
     231         356 :       REAL(dp), DIMENSION(:, :), POINTER                 :: block_dp
     232             :       TYPE(dbcsr_iterator_type)                          :: iter
     233             :       TYPE(dbcsr_type)                                   :: matrix_bs
     234             : 
     235         356 :       CALL timeset(routineN, handle)
     236             : 
     237             :       datatype = dbcsr_get_data_type(matrix_s) ! could be single or double precision
     238             : 
     239             :       ! first generate a block diagonal copy of s
     240         356 :       CALL dbcsr_create(matrix_bs, template=matrix_s)
     241             : 
     242         712 :       SELECT CASE (preconditioner_type)
     243             :       CASE (ls_s_preconditioner_none)
     244             :       CASE (ls_s_preconditioner_atomic, ls_s_preconditioner_molecular)
     245         356 :          CALL dbcsr_iterator_start(iter, matrix_s)
     246       28007 :          DO WHILE (dbcsr_iterator_blocks_left(iter))
     247       27651 :             CALL dbcsr_iterator_next_block(iter, iblock_row, iblock_col, block_dp)
     248             : 
     249             :             ! do we need the block ?
     250             :             ! this depends on the preconditioner, but also the matrix clustering method employed
     251             :             ! for a clustered matrix, right now, we assume that atomic and molecular preconditioners
     252             :             ! are actually the same, and only require that the diagonal blocks (clustered) are present
     253             : 
     254       27651 :             block_needed = .FALSE.
     255             : 
     256       27651 :             IF (iblock_row == iblock_col) THEN
     257             :                block_needed = .TRUE.
     258             :             ELSE
     259       24745 :                IF (preconditioner_type == ls_s_preconditioner_molecular .AND. &
     260             :                    ls_mstruct%cluster_type == ls_cluster_atomic) THEN
     261        5098 :                   IF (ls_mstruct%atom_to_molecule(iblock_row) == ls_mstruct%atom_to_molecule(iblock_col)) block_needed = .TRUE.
     262             :                END IF
     263             :             END IF
     264             : 
     265             :             ! add it
     266         356 :             IF (block_needed) THEN
     267        4094 :                CALL dbcsr_put_block(matrix=matrix_bs, row=iblock_row, col=iblock_col, block=block_dp)
     268             :             END IF
     269             : 
     270             :          END DO
     271         712 :          CALL dbcsr_iterator_stop(iter)
     272             :       END SELECT
     273             : 
     274         356 :       CALL dbcsr_finalize(matrix_bs)
     275             : 
     276         356 :       SELECT CASE (preconditioner_type)
     277             :       CASE (ls_s_preconditioner_none)
     278             :          ! for now make it a simple identity matrix
     279           0 :          CALL dbcsr_copy(matrix_bs_sqrt, matrix_bs)
     280           0 :          CALL dbcsr_set(matrix_bs_sqrt, 0.0_dp)
     281           0 :          CALL dbcsr_add_on_diag(matrix_bs_sqrt, 1.0_dp)
     282             : 
     283             :          ! for now make it a simple identity matrix
     284           0 :          CALL dbcsr_copy(matrix_bs_sqrt_inv, matrix_bs)
     285           0 :          CALL dbcsr_set(matrix_bs_sqrt_inv, 0.0_dp)
     286           0 :          CALL dbcsr_add_on_diag(matrix_bs_sqrt_inv, 1.0_dp)
     287             :       CASE (ls_s_preconditioner_atomic, ls_s_preconditioner_molecular)
     288         356 :          CALL dbcsr_copy(matrix_bs_sqrt, matrix_bs)
     289         356 :          CALL dbcsr_copy(matrix_bs_sqrt_inv, matrix_bs)
     290             :          ! XXXXXXXXXXX
     291             :          ! XXXXXXXXXXX the threshold here could be done differently,
     292             :          ! XXXXXXXXXXX using eps_filter is reducing accuracy for no good reason, this is cheap
     293             :          ! XXXXXXXXXXX
     294             :          CALL matrix_sqrt_Newton_Schulz(matrix_bs_sqrt, matrix_bs_sqrt_inv, matrix_bs, &
     295             :                                         threshold=MIN(threshold, 1.0E-10_dp), order=order, &
     296             :                                         eps_lanczos=eps_lanczos, max_iter_lanczos=max_iter_lanczos, &
     297         712 :                                         iounit=-1)
     298             :       END SELECT
     299             : 
     300         356 :       CALL dbcsr_release(matrix_bs)
     301             : 
     302         356 :       CALL timestop(handle)
     303             : 
     304         356 :    END SUBROUTINE compute_matrix_preconditioner
     305             : 
     306             : ! **************************************************************************************************
     307             : !> \brief apply a preconditioner either
     308             : !>        forward (precondition)            inv(sqrt(bs)) * A * inv(sqrt(bs))
     309             : !>        backward (restore to old form)        sqrt(bs)  * A * sqrt(bs)
     310             : !> \param matrix ...
     311             : !> \param direction ...
     312             : !> \param matrix_bs_sqrt ...
     313             : !> \param matrix_bs_sqrt_inv ...
     314             : !> \par History
     315             : !>       2010.10 created [Joost VandeVondele]
     316             : !> \author Joost VandeVondele
     317             : ! **************************************************************************************************
     318        3614 :    SUBROUTINE apply_matrix_preconditioner(matrix, direction, matrix_bs_sqrt, matrix_bs_sqrt_inv)
     319             : 
     320             :       TYPE(dbcsr_type), INTENT(INOUT)                    :: matrix
     321             :       CHARACTER(LEN=*)                                   :: direction
     322             :       TYPE(dbcsr_type), INTENT(INOUT)                    :: matrix_bs_sqrt, matrix_bs_sqrt_inv
     323             : 
     324             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'apply_matrix_preconditioner'
     325             : 
     326             :       INTEGER                                            :: handle
     327             :       TYPE(dbcsr_type)                                   :: matrix_tmp
     328             : 
     329        3614 :       CALL timeset(routineN, handle)
     330        3614 :       CALL dbcsr_create(matrix_tmp, template=matrix, matrix_type=dbcsr_type_no_symmetry)
     331             : 
     332        3146 :       SELECT CASE (direction)
     333             :       CASE ("forward")
     334             :          CALL dbcsr_multiply("N", "N", 1.0_dp, matrix, matrix_bs_sqrt_inv, &
     335        3146 :                              0.0_dp, matrix_tmp)
     336             :          CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_bs_sqrt_inv, matrix_tmp, &
     337        3146 :                              0.0_dp, matrix)
     338             :       CASE ("backward")
     339             :          CALL dbcsr_multiply("N", "N", 1.0_dp, matrix, matrix_bs_sqrt, &
     340         468 :                              0.0_dp, matrix_tmp)
     341             :          CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_bs_sqrt, matrix_tmp, &
     342         468 :                              0.0_dp, matrix)
     343             :       CASE DEFAULT
     344        3614 :          CPABORT("")
     345             :       END SELECT
     346             : 
     347        3614 :       CALL dbcsr_release(matrix_tmp)
     348             : 
     349        3614 :       CALL timestop(handle)
     350             : 
     351        3614 :    END SUBROUTINE apply_matrix_preconditioner
     352             : 
     353             : ! **************************************************************************************************
     354             : !> \brief compute the density matrix with a trace that is close to nelectron.
     355             : !>        take a mu as input, and improve by bisection as needed.
     356             : !> \param matrix_p ...
     357             : !> \param mu ...
     358             : !> \param fixed_mu ...
     359             : !> \param sign_method ...
     360             : !> \param sign_order ...
     361             : !> \param matrix_ks ...
     362             : !> \param matrix_s ...
     363             : !> \param matrix_s_inv ...
     364             : !> \param nelectron ...
     365             : !> \param threshold ...
     366             : !> \param sign_symmetric ...
     367             : !> \param submatrix_sign_method ...
     368             : !> \param matrix_s_sqrt_inv ...
     369             : !> \par History
     370             : !>       2010.10 created [Joost VandeVondele]
     371             : !>       2020.07 support for methods with internal mu adjustment [Michael Lass]
     372             : !> \author Joost VandeVondele
     373             : ! **************************************************************************************************
     374         910 :    SUBROUTINE density_matrix_sign(matrix_p, mu, fixed_mu, sign_method, sign_order, matrix_ks, &
     375             :                                   matrix_s, matrix_s_inv, nelectron, threshold, sign_symmetric, submatrix_sign_method, &
     376             :                                   matrix_s_sqrt_inv)
     377             : 
     378             :       TYPE(dbcsr_type), INTENT(INOUT)                    :: matrix_p
     379             :       REAL(KIND=dp), INTENT(INOUT)                       :: mu
     380             :       LOGICAL                                            :: fixed_mu
     381             :       INTEGER                                            :: sign_method, sign_order
     382             :       TYPE(dbcsr_type), INTENT(INOUT)                    :: matrix_ks, matrix_s, matrix_s_inv
     383             :       INTEGER, INTENT(IN)                                :: nelectron
     384             :       REAL(KIND=dp), INTENT(IN)                          :: threshold
     385             :       LOGICAL, OPTIONAL                                  :: sign_symmetric
     386             :       INTEGER, OPTIONAL                                  :: submatrix_sign_method
     387             :       TYPE(dbcsr_type), INTENT(IN), OPTIONAL             :: matrix_s_sqrt_inv
     388             : 
     389             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'density_matrix_sign'
     390             :       REAL(KIND=dp), PARAMETER                           :: initial_increment = 0.01_dp
     391             : 
     392             :       INTEGER                                            :: handle, iter, unit_nr, &
     393             :                                                             used_submatrix_sign_method
     394             :       LOGICAL                                            :: do_sign_symmetric, has_mu_high, &
     395             :                                                             has_mu_low, internal_mu_adjust
     396             :       REAL(KIND=dp)                                      :: increment, mu_high, mu_low, trace
     397             :       TYPE(cp_logger_type), POINTER                      :: logger
     398             : 
     399         910 :       CALL timeset(routineN, handle)
     400             : 
     401         910 :       logger => cp_get_default_logger()
     402         910 :       IF (logger%para_env%is_source()) THEN
     403         455 :          unit_nr = cp_logger_get_default_unit_nr(logger, local=.TRUE.)
     404             :       ELSE
     405             :          unit_nr = -1
     406             :       END IF
     407             : 
     408         910 :       do_sign_symmetric = .FALSE.
     409         910 :       IF (PRESENT(sign_symmetric)) do_sign_symmetric = sign_symmetric
     410             : 
     411         910 :       used_submatrix_sign_method = ls_scf_submatrix_sign_ns
     412         910 :       IF (PRESENT(submatrix_sign_method)) used_submatrix_sign_method = submatrix_sign_method
     413             : 
     414             :       internal_mu_adjust = ((sign_method .EQ. ls_scf_sign_submatrix) .AND. &
     415             :                             (used_submatrix_sign_method .EQ. ls_scf_submatrix_sign_direct_muadj .OR. &
     416         910 :                              used_submatrix_sign_method .EQ. ls_scf_submatrix_sign_direct_muadj_lowmem))
     417             : 
     418           4 :       IF (internal_mu_adjust) THEN
     419             :          CALL density_matrix_sign_internal_mu(matrix_p, trace, mu, sign_method, &
     420             :                                               matrix_ks, matrix_s, threshold, &
     421             :                                               used_submatrix_sign_method, &
     422           4 :                                               nelectron, matrix_s_sqrt_inv)
     423             :       ELSE
     424         906 :          increment = initial_increment
     425             : 
     426         906 :          has_mu_low = .FALSE.
     427         906 :          has_mu_high = .FALSE.
     428             : 
     429             :          ! bisect if both bounds are known, otherwise find the bounds with a linear search
     430        1050 :          DO iter = 1, 30
     431        1050 :             IF (has_mu_low .AND. has_mu_high) THEN
     432          16 :                mu = (mu_low + mu_high)/2
     433          16 :                IF (ABS(mu_high - mu_low) < threshold) EXIT
     434             :             END IF
     435             : 
     436             :             CALL density_matrix_sign_fixed_mu(matrix_p, trace, mu, sign_method, sign_order, &
     437             :                                               matrix_ks, matrix_s, matrix_s_inv, threshold, &
     438             :                                               do_sign_symmetric, used_submatrix_sign_method, &
     439        1050 :                                               matrix_s_sqrt_inv)
     440        1050 :             IF (unit_nr > 0) WRITE (unit_nr, '(T2,A,I2,1X,F13.9,1X,F15.9)') &
     441         525 :                "Density matrix:  iter, mu, trace error: ", iter, mu, trace - nelectron
     442             : 
     443             :             ! OK, we can skip early if we are as close as possible to the exact result
     444             :             ! smaller differences should be considered 'noise'
     445        1050 :             IF (ABS(trace - nelectron) < 0.5_dp .OR. fixed_mu) EXIT
     446             : 
     447        2100 :             IF (trace < nelectron) THEN
     448          32 :                mu_low = mu
     449          32 :                mu = mu + increment
     450          32 :                has_mu_low = .TRUE.
     451          32 :                increment = increment*2
     452             :             ELSE
     453         112 :                mu_high = mu
     454         112 :                mu = mu - increment
     455         112 :                has_mu_high = .TRUE.
     456         112 :                increment = increment*2
     457             :             END IF
     458             :          END DO
     459             : 
     460             :       END IF
     461             : 
     462         910 :       CALL timestop(handle)
     463             : 
     464         910 :    END SUBROUTINE density_matrix_sign
     465             : 
     466             : ! **************************************************************************************************
     467             : !> \brief for a fixed mu, compute the corresponding density matrix and its trace
     468             : !> \param matrix_p ...
     469             : !> \param trace ...
     470             : !> \param mu ...
     471             : !> \param sign_method ...
     472             : !> \param sign_order ...
     473             : !> \param matrix_ks ...
     474             : !> \param matrix_s ...
     475             : !> \param matrix_s_inv ...
     476             : !> \param threshold ...
     477             : !> \param sign_symmetric ...
     478             : !> \param submatrix_sign_method ...
     479             : !> \param matrix_s_sqrt_inv ...
     480             : !> \par History
     481             : !>       2010.10 created [Joost VandeVondele]
     482             : !> \author Joost VandeVondele
     483             : ! **************************************************************************************************
     484        2144 :    SUBROUTINE density_matrix_sign_fixed_mu(matrix_p, trace, mu, sign_method, sign_order, matrix_ks, &
     485             :                                            matrix_s, matrix_s_inv, threshold, sign_symmetric, submatrix_sign_method, &
     486             :                                            matrix_s_sqrt_inv)
     487             : 
     488             :       TYPE(dbcsr_type), INTENT(INOUT)                    :: matrix_p
     489             :       REAL(KIND=dp), INTENT(OUT)                         :: trace
     490             :       REAL(KIND=dp), INTENT(INOUT)                       :: mu
     491             :       INTEGER                                            :: sign_method, sign_order
     492             :       TYPE(dbcsr_type), INTENT(INOUT)                    :: matrix_ks, matrix_s, matrix_s_inv
     493             :       REAL(KIND=dp), INTENT(IN)                          :: threshold
     494             :       LOGICAL                                            :: sign_symmetric
     495             :       INTEGER                                            :: submatrix_sign_method
     496             :       TYPE(dbcsr_type), INTENT(IN), OPTIONAL             :: matrix_s_sqrt_inv
     497             : 
     498             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'density_matrix_sign_fixed_mu'
     499             : 
     500             :       INTEGER                                            :: handle, unit_nr
     501             :       REAL(KIND=dp)                                      :: frob_matrix
     502             :       TYPE(cp_logger_type), POINTER                      :: logger
     503             :       TYPE(dbcsr_type) :: matrix_p_ud, matrix_sign, matrix_sinv_ks, matrix_ssqrtinv_ks_ssqrtinv, &
     504             :          matrix_ssqrtinv_ks_ssqrtinv2, matrix_tmp
     505             : 
     506        1072 :       CALL timeset(routineN, handle)
     507             : 
     508        1072 :       logger => cp_get_default_logger()
     509        1072 :       IF (logger%para_env%is_source()) THEN
     510         536 :          unit_nr = cp_logger_get_default_unit_nr(logger, local=.TRUE.)
     511             :       ELSE
     512             :          unit_nr = -1
     513             :       END IF
     514             : 
     515        1072 :       CALL dbcsr_create(matrix_sign, template=matrix_s, matrix_type=dbcsr_type_no_symmetry)
     516             : 
     517        1072 :       IF (sign_symmetric) THEN
     518             : 
     519           4 :          IF (.NOT. PRESENT(matrix_s_sqrt_inv)) &
     520           0 :             CPABORT("Argument matrix_s_sqrt_inv required if sign_symmetric is set")
     521             : 
     522           4 :          CALL dbcsr_create(matrix_ssqrtinv_ks_ssqrtinv, template=matrix_s, matrix_type=dbcsr_type_no_symmetry)
     523           4 :          CALL dbcsr_create(matrix_ssqrtinv_ks_ssqrtinv2, template=matrix_s, matrix_type=dbcsr_type_no_symmetry)
     524             :          CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_s_sqrt_inv, matrix_ks, &
     525           4 :                              0.0_dp, matrix_ssqrtinv_ks_ssqrtinv2, filter_eps=threshold)
     526             :          CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_ssqrtinv_ks_ssqrtinv2, matrix_s_sqrt_inv, &
     527           4 :                              0.0_dp, matrix_ssqrtinv_ks_ssqrtinv, filter_eps=threshold)
     528           4 :          CALL dbcsr_add_on_diag(matrix_ssqrtinv_ks_ssqrtinv, -mu)
     529             : 
     530           6 :          SELECT CASE (sign_method)
     531             :          CASE (ls_scf_sign_ns)
     532           2 :             CALL matrix_sign_Newton_Schulz(matrix_sign, matrix_ssqrtinv_ks_ssqrtinv, threshold, sign_order, iounit=-1)
     533             :          CASE (ls_scf_sign_proot)
     534           0 :             CALL matrix_sign_proot(matrix_sign, matrix_ssqrtinv_ks_ssqrtinv, threshold, sign_order)
     535             :          CASE (ls_scf_sign_submatrix)
     536           2 :             CALL matrix_sign_submatrix(matrix_sign, matrix_ssqrtinv_ks_ssqrtinv, threshold, sign_order, submatrix_sign_method)
     537             :          CASE DEFAULT
     538           4 :             CPABORT("Unkown sign method.")
     539             :          END SELECT
     540           4 :          CALL dbcsr_release(matrix_ssqrtinv_ks_ssqrtinv)
     541           4 :          CALL dbcsr_release(matrix_ssqrtinv_ks_ssqrtinv2)
     542             : 
     543             :       ELSE ! .NOT. sign_symmetric
     544             :          ! get inv(S)*H-I*mu
     545        1068 :          CALL dbcsr_create(matrix_sinv_ks, template=matrix_s, matrix_type=dbcsr_type_no_symmetry)
     546             :          CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_s_inv, matrix_ks, &
     547        1068 :                              0.0_dp, matrix_sinv_ks, filter_eps=threshold)
     548        1068 :          CALL dbcsr_add_on_diag(matrix_sinv_ks, -mu)
     549             : 
     550             :          ! compute sign(inv(S)*H-I*mu)
     551        2124 :          SELECT CASE (sign_method)
     552             :          CASE (ls_scf_sign_ns)
     553        1056 :             CALL matrix_sign_Newton_Schulz(matrix_sign, matrix_sinv_ks, threshold, sign_order, iounit=-1)
     554             :          CASE (ls_scf_sign_proot)
     555           8 :             CALL matrix_sign_proot(matrix_sign, matrix_sinv_ks, threshold, sign_order)
     556             :          CASE (ls_scf_sign_submatrix)
     557           4 :             CALL matrix_sign_submatrix(matrix_sign, matrix_sinv_ks, threshold, sign_order, submatrix_sign_method)
     558             :          CASE DEFAULT
     559        1068 :             CPABORT("Unkown sign method.")
     560             :          END SELECT
     561        1068 :          CALL dbcsr_release(matrix_sinv_ks)
     562             :       END IF
     563             : 
     564             :       ! now construct the density matrix PS=0.5*(I-sign(inv(S)H-I*mu))
     565        1072 :       CALL dbcsr_create(matrix_p_ud, template=matrix_s, matrix_type=dbcsr_type_no_symmetry)
     566        1072 :       CALL dbcsr_copy(matrix_p_ud, matrix_sign)
     567        1072 :       CALL dbcsr_scale(matrix_p_ud, -0.5_dp)
     568        1072 :       CALL dbcsr_add_on_diag(matrix_p_ud, 0.5_dp)
     569        1072 :       CALL dbcsr_release(matrix_sign)
     570             : 
     571             :       ! we now have PS, lets get its trace
     572        1072 :       CALL dbcsr_trace(matrix_p_ud, trace)
     573             : 
     574             :       ! we can also check it is idempotent PS*PS=PS
     575        1072 :       CALL dbcsr_create(matrix_tmp, template=matrix_s, matrix_type=dbcsr_type_no_symmetry)
     576             :       CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_p_ud, matrix_p_ud, &
     577        1072 :                           0.0_dp, matrix_tmp, filter_eps=threshold)
     578        1072 :       CALL dbcsr_add(matrix_tmp, matrix_p_ud, 1.0_dp, -1.0_dp)
     579        1072 :       frob_matrix = dbcsr_frobenius_norm(matrix_tmp)
     580        1072 :       IF (unit_nr > 0 .AND. frob_matrix > 0.001_dp) &
     581          30 :          WRITE (unit_nr, '(T2,A,F20.12)') "Deviation from idempotency: ", frob_matrix
     582             : 
     583        1072 :       IF (sign_symmetric) THEN
     584             :          CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_s_sqrt_inv, matrix_p_ud, &
     585           4 :                              0.0_dp, matrix_tmp, filter_eps=threshold)
     586             :          CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_tmp, matrix_s_sqrt_inv, &
     587           4 :                              0.0_dp, matrix_p, filter_eps=threshold)
     588             :       ELSE
     589             : 
     590             :          ! get P=PS*inv(S)
     591             :          CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_p_ud, matrix_s_inv, &
     592        1068 :                              0.0_dp, matrix_p, filter_eps=threshold)
     593             :       END IF
     594        1072 :       CALL dbcsr_release(matrix_p_ud)
     595        1072 :       CALL dbcsr_release(matrix_tmp)
     596             : 
     597        1072 :       CALL timestop(handle)
     598             : 
     599        1072 :    END SUBROUTINE density_matrix_sign_fixed_mu
     600             : 
     601             : ! **************************************************************************************************
     602             : !> \brief compute the corresponding density matrix and its trace, using methods with internal mu adjustment
     603             : !> \param matrix_p ...
     604             : !> \param trace ...
     605             : !> \param mu ...
     606             : !> \param sign_method ...
     607             : !> \param matrix_ks ...
     608             : !> \param matrix_s ...
     609             : !> \param threshold ...
     610             : !> \param submatrix_sign_method ...
     611             : !> \param nelectron ...
     612             : !> \param matrix_s_sqrt_inv ...
     613             : !> \par History
     614             : !>       2020.07 created, based on density_matrix_sign_fixed_mu [Michael Lass]
     615             : !> \author Michael Lass
     616             : ! **************************************************************************************************
     617           8 :    SUBROUTINE density_matrix_sign_internal_mu(matrix_p, trace, mu, sign_method, matrix_ks, &
     618             :                                               matrix_s, threshold, submatrix_sign_method, &
     619             :                                               nelectron, matrix_s_sqrt_inv)
     620             : 
     621             :       TYPE(dbcsr_type), INTENT(INOUT)                    :: matrix_p
     622             :       REAL(KIND=dp), INTENT(OUT)                         :: trace
     623             :       REAL(KIND=dp), INTENT(INOUT)                       :: mu
     624             :       INTEGER                                            :: sign_method
     625             :       TYPE(dbcsr_type), INTENT(INOUT)                    :: matrix_ks, matrix_s
     626             :       REAL(KIND=dp), INTENT(IN)                          :: threshold
     627             :       INTEGER                                            :: submatrix_sign_method
     628             :       INTEGER, INTENT(IN)                                :: nelectron
     629             :       TYPE(dbcsr_type), INTENT(IN)                       :: matrix_s_sqrt_inv
     630             : 
     631             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'density_matrix_sign_internal_mu'
     632             : 
     633             :       INTEGER                                            :: handle, unit_nr
     634             :       REAL(KIND=dp)                                      :: frob_matrix
     635             :       TYPE(cp_logger_type), POINTER                      :: logger
     636             :       TYPE(dbcsr_type)                                   :: matrix_p_ud, matrix_sign, &
     637             :                                                             matrix_ssqrtinv_ks_ssqrtinv, &
     638             :                                                             matrix_ssqrtinv_ks_ssqrtinv2, &
     639             :                                                             matrix_tmp
     640             : 
     641           4 :       CALL timeset(routineN, handle)
     642             : 
     643           4 :       logger => cp_get_default_logger()
     644           4 :       IF (logger%para_env%is_source()) THEN
     645           2 :          unit_nr = cp_logger_get_default_unit_nr(logger, local=.TRUE.)
     646             :       ELSE
     647             :          unit_nr = -1
     648             :       END IF
     649             : 
     650           4 :       CALL dbcsr_create(matrix_sign, template=matrix_s, matrix_type=dbcsr_type_no_symmetry)
     651             : 
     652           4 :       CALL dbcsr_create(matrix_ssqrtinv_ks_ssqrtinv, template=matrix_s, matrix_type=dbcsr_type_no_symmetry)
     653           4 :       CALL dbcsr_create(matrix_ssqrtinv_ks_ssqrtinv2, template=matrix_s, matrix_type=dbcsr_type_no_symmetry)
     654             :       CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_s_sqrt_inv, matrix_ks, &
     655           4 :                           0.0_dp, matrix_ssqrtinv_ks_ssqrtinv2, filter_eps=threshold)
     656             :       CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_ssqrtinv_ks_ssqrtinv2, matrix_s_sqrt_inv, &
     657           4 :                           0.0_dp, matrix_ssqrtinv_ks_ssqrtinv, filter_eps=threshold)
     658           4 :       CALL dbcsr_add_on_diag(matrix_ssqrtinv_ks_ssqrtinv, -mu)
     659             : 
     660           8 :       SELECT CASE (sign_method)
     661             :       CASE (ls_scf_sign_submatrix)
     662           8 :          SELECT CASE (submatrix_sign_method)
     663             :          CASE (ls_scf_submatrix_sign_direct_muadj, ls_scf_submatrix_sign_direct_muadj_lowmem)
     664             :             CALL matrix_sign_submatrix_mu_adjust(matrix_sign, matrix_ssqrtinv_ks_ssqrtinv, mu, nelectron, threshold, &
     665           4 :                                                  submatrix_sign_method)
     666             :          CASE DEFAULT
     667           4 :             CPABORT("density_matrix_sign_internal_mu called with invalid submatrix sign method")
     668             :          END SELECT
     669             :       CASE DEFAULT
     670           4 :          CPABORT("density_matrix_sign_internal_mu called with invalid sign method.")
     671             :       END SELECT
     672           4 :       CALL dbcsr_release(matrix_ssqrtinv_ks_ssqrtinv)
     673           4 :       CALL dbcsr_release(matrix_ssqrtinv_ks_ssqrtinv2)
     674             : 
     675             :       ! now construct the density matrix PS=0.5*(I-sign(inv(S)H-I*mu))
     676           4 :       CALL dbcsr_create(matrix_p_ud, template=matrix_s, matrix_type=dbcsr_type_no_symmetry)
     677           4 :       CALL dbcsr_copy(matrix_p_ud, matrix_sign)
     678           4 :       CALL dbcsr_scale(matrix_p_ud, -0.5_dp)
     679           4 :       CALL dbcsr_add_on_diag(matrix_p_ud, 0.5_dp)
     680           4 :       CALL dbcsr_release(matrix_sign)
     681             : 
     682             :       ! we now have PS, lets get its trace
     683           4 :       CALL dbcsr_trace(matrix_p_ud, trace)
     684             : 
     685             :       ! we can also check it is idempotent PS*PS=PS
     686           4 :       CALL dbcsr_create(matrix_tmp, template=matrix_s, matrix_type=dbcsr_type_no_symmetry)
     687             :       CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_p_ud, matrix_p_ud, &
     688           4 :                           0.0_dp, matrix_tmp, filter_eps=threshold)
     689           4 :       CALL dbcsr_add(matrix_tmp, matrix_p_ud, 1.0_dp, -1.0_dp)
     690           4 :       frob_matrix = dbcsr_frobenius_norm(matrix_tmp)
     691           4 :       IF (unit_nr > 0 .AND. frob_matrix > 0.001_dp) &
     692           0 :          WRITE (unit_nr, '(T2,A,F20.12)') "Deviation from idempotency: ", frob_matrix
     693             : 
     694             :       CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_s_sqrt_inv, matrix_p_ud, &
     695           4 :                           0.0_dp, matrix_tmp, filter_eps=threshold)
     696             :       CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_tmp, matrix_s_sqrt_inv, &
     697           4 :                           0.0_dp, matrix_p, filter_eps=threshold)
     698           4 :       CALL dbcsr_release(matrix_p_ud)
     699           4 :       CALL dbcsr_release(matrix_tmp)
     700             : 
     701           4 :       CALL timestop(handle)
     702             : 
     703           4 :    END SUBROUTINE density_matrix_sign_internal_mu
     704             : 
     705             : ! **************************************************************************************************
     706             : !> \brief compute the density matrix using a trace-resetting algorithm
     707             : !> \param matrix_p ...
     708             : !> \param matrix_ks ...
     709             : !> \param matrix_s_sqrt_inv ...
     710             : !> \param nelectron ...
     711             : !> \param threshold ...
     712             : !> \param e_homo ...
     713             : !> \param e_lumo ...
     714             : !> \param e_mu ...
     715             : !> \param dynamic_threshold ...
     716             : !> \param matrix_ks_deviation ...
     717             : !> \param max_iter_lanczos ...
     718             : !> \param eps_lanczos ...
     719             : !> \param converged ...
     720             : !> \param iounit ...
     721             : !> \par History
     722             : !>       2012.06 created [Florian Thoele]
     723             : !> \author Florian Thoele
     724             : ! **************************************************************************************************
     725       13720 :    SUBROUTINE density_matrix_trs4(matrix_p, matrix_ks, matrix_s_sqrt_inv, &
     726             :                                   nelectron, threshold, e_homo, e_lumo, e_mu, &
     727             :                                   dynamic_threshold, matrix_ks_deviation, &
     728             :                                   max_iter_lanczos, eps_lanczos, converged, iounit)
     729             : 
     730             :       TYPE(dbcsr_type), INTENT(INOUT)                    :: matrix_p
     731             :       TYPE(dbcsr_type), INTENT(IN)                       :: matrix_ks, matrix_s_sqrt_inv
     732             :       INTEGER, INTENT(IN)                                :: nelectron
     733             :       REAL(KIND=dp), INTENT(IN)                          :: threshold
     734             :       REAL(KIND=dp), INTENT(INOUT)                       :: e_homo, e_lumo, e_mu
     735             :       LOGICAL, INTENT(IN), OPTIONAL                      :: dynamic_threshold
     736             :       TYPE(dbcsr_type), INTENT(INOUT), OPTIONAL          :: matrix_ks_deviation
     737             :       INTEGER, INTENT(IN)                                :: max_iter_lanczos
     738             :       REAL(KIND=dp), INTENT(IN)                          :: eps_lanczos
     739             :       LOGICAL, INTENT(OUT), OPTIONAL                     :: converged
     740             :       INTEGER, INTENT(IN), OPTIONAL                      :: iounit
     741             : 
     742             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'density_matrix_trs4'
     743             :       INTEGER, PARAMETER                                 :: max_iter = 100
     744             :       REAL(KIND=dp), PARAMETER                           :: gamma_max = 6.0_dp, gamma_min = 0.0_dp
     745             : 
     746             :       INTEGER                                            :: branch, estimated_steps, handle, i, j, &
     747             :                                                             unit_nr
     748             :       INTEGER(kind=int_8)                                :: flop1, flop2
     749             :       LOGICAL                                            :: arnoldi_converged, do_dyn_threshold
     750             :       REAL(KIND=dp) :: current_threshold, delta_n, eps_max, eps_min, est_threshold, frob_id, &
     751             :          frob_x, gam, homo, lumo, max_eig, max_threshold, maxdev, maxev, min_eig, minev, mmin, mu, &
     752             :          mu_a, mu_b, mu_c, mu_fa, mu_fc, occ_matrix, scaled_homo_bound, scaled_lumo_bound, t1, t2, &
     753             :          trace_fx, trace_gx, xi
     754       13720 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: gamma_values
     755             :       TYPE(cp_logger_type), POINTER                      :: logger
     756             :       TYPE(dbcsr_type)                                   :: matrix_k0, matrix_x, matrix_x_nosym, &
     757             :                                                             matrix_xidsq, matrix_xsq, tmp_gx
     758             : 
     759       13720 :       IF (nelectron == 0) THEN
     760           0 :          CALL dbcsr_set(matrix_p, 0.0_dp)
     761             :          RETURN
     762             :       END IF
     763             : 
     764       13720 :       CALL timeset(routineN, handle)
     765             : 
     766       13720 :       IF (PRESENT(iounit)) THEN
     767        1876 :          unit_nr = iounit
     768             :       ELSE
     769       11844 :          logger => cp_get_default_logger()
     770       11844 :          IF (logger%para_env%is_source()) THEN
     771        5922 :             unit_nr = cp_logger_get_default_unit_nr(logger, local=.TRUE.)
     772             :          ELSE
     773        5922 :             unit_nr = -1
     774             :          END IF
     775             :       END IF
     776             : 
     777       13720 :       do_dyn_threshold = .FALSE.
     778       13720 :       IF (PRESENT(dynamic_threshold)) do_dyn_threshold = dynamic_threshold
     779             : 
     780       13720 :       IF (PRESENT(converged)) converged = .FALSE.
     781             : 
     782             :       ! init X = (eps_n*I - H)/(eps_n - eps_0)  ... H* = S^-1/2*H*S^-1/2
     783       13720 :       CALL dbcsr_create(matrix_x, template=matrix_ks, matrix_type="S")
     784             : 
     785             :       ! at some points the non-symmetric version of x is required
     786       13720 :       CALL dbcsr_create(matrix_x_nosym, template=matrix_ks, matrix_type=dbcsr_type_no_symmetry)
     787             : 
     788             :       CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_s_sqrt_inv, matrix_ks, &
     789       13720 :                           0.0_dp, matrix_x_nosym, filter_eps=threshold)
     790             :       CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_x_nosym, matrix_s_sqrt_inv, &
     791       13720 :                           0.0_dp, matrix_x, filter_eps=threshold)
     792       13720 :       CALL dbcsr_desymmetrize(matrix_x, matrix_x_nosym)
     793             : 
     794       13720 :       CALL dbcsr_create(matrix_k0, template=matrix_ks, matrix_type=dbcsr_type_no_symmetry)
     795       13720 :       CALL dbcsr_copy(matrix_k0, matrix_x_nosym)
     796             : 
     797             :       ! compute the deviation in the mixed matrix, as seen in the ortho basis
     798       13720 :       IF (do_dyn_threshold) THEN
     799          24 :          CPASSERT(PRESENT(matrix_ks_deviation))
     800          24 :          CALL dbcsr_add(matrix_ks_deviation, matrix_x_nosym, -1.0_dp, 1.0_dp)
     801             :          CALL arnoldi_extremal(matrix_ks_deviation, maxev, minev, max_iter=max_iter_lanczos, threshold=eps_lanczos, &
     802          24 :                                converged=arnoldi_converged)
     803          24 :          maxdev = MAX(ABS(maxev), ABS(minev))
     804          24 :          IF (unit_nr > 0) THEN
     805           0 :             WRITE (unit_nr, '(T6,A,1X,L12)') "Lanczos converged:      ", arnoldi_converged
     806           0 :             WRITE (unit_nr, '(T6,A,1X,F12.5)') "change in mixed matrix: ", maxdev
     807           0 :             WRITE (unit_nr, '(T6,A,1X,F12.5)') "HOMO upper bound:       ", e_homo + maxdev
     808           0 :             WRITE (unit_nr, '(T6,A,1X,F12.5)') "LUMO lower bound:       ", e_lumo - maxdev
     809           0 :             WRITE (unit_nr, '(T6,A,1X,L12)') "Predicts a gap ?        ", ((e_lumo - maxdev) - (e_homo + maxdev)) > 0
     810             :          END IF
     811             :          ! save the old mixed matrix
     812          24 :          CALL dbcsr_copy(matrix_ks_deviation, matrix_x_nosym)
     813             : 
     814             :       END IF
     815             : 
     816             :       ! get largest/smallest eigenvalues for scaling
     817             :       CALL arnoldi_extremal(matrix_x_nosym, max_eig, min_eig, max_iter=max_iter_lanczos, threshold=eps_lanczos, &
     818       13720 :                             converged=arnoldi_converged)
     819       19642 :       IF (unit_nr > 0) WRITE (unit_nr, '(T6,A,1X,2F12.5,1X,A,1X,L1)') "Est. extremal eigenvalues", &
     820       11844 :          min_eig, max_eig, " converged: ", arnoldi_converged
     821       13720 :       eps_max = max_eig
     822       13720 :       eps_min = min_eig
     823             : 
     824             :       ! scale KS matrix
     825       13720 :       IF (eps_max == eps_min) THEN
     826          20 :          CALL dbcsr_scale(matrix_x, 1.0_dp/eps_max)
     827             :       ELSE
     828       13700 :          CALL dbcsr_add_on_diag(matrix_x, -eps_max)
     829       13700 :          CALL dbcsr_scale(matrix_x, -1.0_dp/(eps_max - eps_min))
     830             :       END IF
     831             : 
     832       13720 :       current_threshold = threshold
     833       13720 :       IF (do_dyn_threshold) THEN
     834             :          ! scale bounds for HOMO/LUMO
     835          24 :          scaled_homo_bound = (eps_max - (e_homo + maxdev))/(eps_max - eps_min)
     836          24 :          scaled_lumo_bound = (eps_max - (e_lumo - maxdev))/(eps_max - eps_min)
     837             :       END IF
     838             : 
     839       13720 :       CALL dbcsr_create(matrix_xsq, template=matrix_ks, matrix_type="S")
     840             : 
     841       13720 :       CALL dbcsr_create(matrix_xidsq, template=matrix_ks, matrix_type="S")
     842             : 
     843       13720 :       CALL dbcsr_create(tmp_gx, template=matrix_ks, matrix_type="S")
     844             : 
     845       13720 :       ALLOCATE (gamma_values(max_iter))
     846             : 
     847       70588 :       DO i = 1, max_iter
     848       70588 :          t1 = m_walltime()
     849       70588 :          flop1 = 0; flop2 = 0
     850             : 
     851             :          ! get X*X
     852             :          CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_x, matrix_x, &
     853             :                              0.0_dp, matrix_xsq, &
     854       70588 :                              filter_eps=current_threshold, flop=flop1)
     855             : 
     856             :          ! intermediate use matrix_xidsq to compute = X*X-X
     857       70588 :          CALL dbcsr_copy(matrix_xidsq, matrix_x)
     858       70588 :          CALL dbcsr_add(matrix_xidsq, matrix_xsq, -1.0_dp, 1.0_dp)
     859       70588 :          frob_id = dbcsr_frobenius_norm(matrix_xidsq)
     860       70588 :          frob_x = dbcsr_frobenius_norm(matrix_x)
     861             : 
     862             :          ! xidsq = (1-X)*(1-X)
     863             :          ! use (1-x)*(1-x) = 1 + x*x - 2*x
     864       70588 :          CALL dbcsr_copy(matrix_xidsq, matrix_x)
     865       70588 :          CALL dbcsr_add(matrix_xidsq, matrix_xsq, -2.0_dp, 1.0_dp)
     866       70588 :          CALL dbcsr_add_on_diag(matrix_xidsq, 1.0_dp)
     867             : 
     868             :          ! tmp_gx = 4X-3X*X
     869       70588 :          CALL dbcsr_copy(tmp_gx, matrix_x)
     870       70588 :          CALL dbcsr_add(tmp_gx, matrix_xsq, 4.0_dp, -3.0_dp)
     871             : 
     872             :          ! get gamma
     873             :          ! Tr(F) = Tr(XX*tmp_gx) Tr(G) is equivalent
     874       70588 :          CALL dbcsr_dot(matrix_xsq, matrix_xidsq, trace_gx)
     875       70588 :          CALL dbcsr_dot(matrix_xsq, tmp_gx, trace_fx)
     876             : 
     877             :          ! if converged, and gam becomes noisy, fix it to 3, which results in a final McWeeny step.
     878             :          ! do this only if the electron count is reasonable.
     879             :          ! maybe tune if the current criterion is not good enough
     880       70588 :          delta_n = nelectron - trace_fx
     881             :          ! condition: ABS(frob_id/frob_x) < SQRT(threshold) ...
     882       70588 :          IF (((frob_id*frob_id) < (threshold*frob_x*frob_x)) .AND. (ABS(delta_n) < 0.5_dp)) THEN
     883       13720 :             gam = 3.0_dp
     884       56868 :          ELSE IF (ABS(delta_n) < 1e-14_dp) THEN
     885           0 :             gam = 0.0_dp ! rare case of perfect electron count
     886             :          ELSE
     887             :             ! make sure, we don't divide by zero, as soon as gam is outside the interval gam_min,gam_max, it doesn't matter
     888       56868 :             gam = delta_n/MAX(trace_gx, ABS(delta_n)/100)
     889             :          END IF
     890       70588 :          gamma_values(i) = gam
     891             : 
     892             :          IF (unit_nr > 0 .AND. .FALSE.) THEN
     893             :             WRITE (unit_nr, *) "trace_fx", trace_fx, "trace_gx", trace_gx, "gam", gam, &
     894             :                "frob_id", frob_id, "conv", ABS(frob_id/frob_x)
     895             :          END IF
     896             : 
     897       70588 :          IF (do_dyn_threshold) THEN
     898             :             ! quantities used for dynamic thresholding, when the estimated gap is larger than zero
     899         154 :             xi = (scaled_homo_bound - scaled_lumo_bound)
     900         154 :             IF (xi > 0.0_dp) THEN
     901         130 :                mmin = 0.5*(scaled_homo_bound + scaled_lumo_bound)
     902         130 :                max_threshold = ABS(1 - 2*mmin)*xi
     903             : 
     904         130 :                scaled_homo_bound = evaluate_trs4_polynomial(scaled_homo_bound, gamma_values(i:), 1)
     905         130 :                scaled_lumo_bound = evaluate_trs4_polynomial(scaled_lumo_bound, gamma_values(i:), 1)
     906         130 :                estimated_steps = estimate_steps(scaled_homo_bound, scaled_lumo_bound, threshold)
     907             : 
     908         130 :                est_threshold = (threshold/(estimated_steps + i + 1))*xi/(1 + threshold/(estimated_steps + i + 1))
     909         130 :                est_threshold = MIN(max_threshold, est_threshold)
     910         130 :                IF (i > 1) est_threshold = MAX(est_threshold, 0.1_dp*current_threshold)
     911         130 :                current_threshold = est_threshold
     912             :             ELSE
     913          24 :                current_threshold = threshold
     914             :             END IF
     915             :          END IF
     916             : 
     917       70588 :          IF (gam > gamma_max) THEN
     918             :             ! Xn+1 = 2X-X*X
     919         908 :             CALL dbcsr_add(matrix_x, matrix_xsq, 2.0_dp, -1.0_dp)
     920         908 :             CALL dbcsr_filter(matrix_x, current_threshold)
     921         908 :             branch = 1
     922       69680 :          ELSE IF (gam < gamma_min) THEN
     923             :             ! Xn+1 = X*X
     924        3010 :             CALL dbcsr_copy(matrix_x, matrix_xsq)
     925        3010 :             branch = 2
     926             :          ELSE
     927             :             ! Xn+1 = F(X) + gam*G(X)
     928       66670 :             CALL dbcsr_add(tmp_gx, matrix_xidsq, 1.0_dp, gam)
     929             :             CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_xsq, tmp_gx, &
     930             :                                 0.0_dp, matrix_x, &
     931       66670 :                                 flop=flop2, filter_eps=current_threshold)
     932       66670 :             branch = 3
     933             :          END IF
     934             : 
     935       70588 :          occ_matrix = dbcsr_get_occupation(matrix_x)
     936       70588 :          t2 = m_walltime()
     937       70588 :          IF (unit_nr > 0) THEN
     938             :             WRITE (unit_nr, &
     939       30158 :                    '(T6,A,I3,1X,F10.8,E12.3,F12.3,F13.3,E12.3)') "TRS4 it ", &
     940       30158 :                i, occ_matrix, ABS(trace_gx), t2 - t1, &
     941       60316 :                (flop1 + flop2)/(1.0E6_dp*MAX(t2 - t1, 0.001_dp)), current_threshold
     942       30158 :             CALL m_flush(unit_nr)
     943             :          END IF
     944             : 
     945       70588 :          IF (abnormal_value(trace_gx)) &
     946           0 :             CPABORT("trace_gx is an abnormal value (NaN/Inf).")
     947             : 
     948             :          ! a branch of 1 or 2 appears to lead to a less accurate electron number count and premature exit
     949             :          ! if it turns out this does not exit because we get stuck in branch 1/2 for a reason we need to refine further
     950             :          ! condition: ABS(frob_id/frob_x) < SQRT(threshold) ...
     951       70588 :          IF ((frob_id*frob_id) < (threshold*frob_x*frob_x) .AND. branch == 3 .AND. (ABS(delta_n) < 0.5_dp)) THEN
     952       13720 :             IF (PRESENT(converged)) converged = .TRUE.
     953             :             EXIT
     954             :          END IF
     955             : 
     956             :       END DO
     957             : 
     958       13720 :       occ_matrix = dbcsr_get_occupation(matrix_x)
     959       13720 :       IF (unit_nr > 0) WRITE (unit_nr, '(T6,A,I3,1X,F10.8,E12.3)') 'Final TRS4 iteration  ', i, occ_matrix, ABS(trace_gx)
     960             : 
     961             :       ! free some memory
     962       13720 :       CALL dbcsr_release(tmp_gx)
     963       13720 :       CALL dbcsr_release(matrix_xsq)
     964       13720 :       CALL dbcsr_release(matrix_xidsq)
     965             : 
     966             :       ! output to matrix_p, P = inv(S)^0.5 X inv(S)^0.5
     967             :       CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_x, matrix_s_sqrt_inv, &
     968       13720 :                           0.0_dp, matrix_x_nosym, filter_eps=threshold)
     969             :       CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_s_sqrt_inv, matrix_x_nosym, &
     970       13720 :                           0.0_dp, matrix_p, filter_eps=threshold)
     971             : 
     972             :       ! calculate the chemical potential by doing a bisection of fk(x0)-0.5, where fk is evaluated using the stored values for gamma
     973             :       ! E. Rubensson et al., Chem Phys Lett 432, 2006, 591-594
     974       13720 :       mu_a = 0.0_dp; mu_b = 1.0_dp; 
     975       13720 :       mu_fa = evaluate_trs4_polynomial(mu_a, gamma_values, i - 1) - 0.5_dp
     976      162108 :       DO j = 1, 40
     977      162108 :          mu_c = 0.5*(mu_a + mu_b)
     978      162108 :          mu_fc = evaluate_trs4_polynomial(mu_c, gamma_values, i - 1) - 0.5_dp ! i-1 because in the last iteration, only convergence is checked
     979      162108 :          IF (ABS(mu_fc) < 1.0E-6_dp .OR. (mu_b - mu_a)/2 < 1.0E-6_dp) EXIT !TODO: define threshold values
     980             : 
     981      162108 :          IF (mu_fc*mu_fa > 0) THEN
     982       76402 :             mu_a = mu_c
     983       76402 :             mu_fa = mu_fc
     984             :          ELSE
     985             :             mu_b = mu_c
     986             :          END IF
     987             :       END DO
     988       13720 :       mu = (eps_min - eps_max)*mu_c + eps_max
     989       13720 :       DEALLOCATE (gamma_values)
     990       13720 :       IF (unit_nr > 0) THEN
     991        5922 :          WRITE (unit_nr, '(T6,A,1X,F12.5)') 'Chemical potential (mu): ', mu
     992             :       END IF
     993       13720 :       e_mu = mu
     994             : 
     995       13720 :       IF (do_dyn_threshold) THEN
     996          24 :          CALL dbcsr_desymmetrize(matrix_x, matrix_x_nosym)
     997             :          CALL compute_homo_lumo(matrix_k0, matrix_x_nosym, eps_min, eps_max, &
     998          24 :                                 threshold, max_iter_lanczos, eps_lanczos, homo, lumo, unit_nr)
     999          24 :          e_homo = homo
    1000          24 :          e_lumo = lumo
    1001             :       END IF
    1002             : 
    1003       13720 :       CALL dbcsr_release(matrix_x)
    1004       13720 :       CALL dbcsr_release(matrix_x_nosym)
    1005       13720 :       CALL dbcsr_release(matrix_k0)
    1006       13720 :       CALL timestop(handle)
    1007             : 
    1008       27440 :    END SUBROUTINE density_matrix_trs4
    1009             : 
    1010             : ! **************************************************************************************************
    1011             : !> \brief compute the density matrix using a non monotonic trace conserving
    1012             : !>  algorithm based on SIAM DOI. 10.1137/130911585.
    1013             : !>       2014.04 created [Jonathan Mullin]
    1014             : !> \param matrix_p ...
    1015             : !> \param matrix_ks ...
    1016             : !> \param matrix_s_sqrt_inv ...
    1017             : !> \param nelectron ...
    1018             : !> \param threshold ...
    1019             : !> \param e_homo ...
    1020             : !> \param e_lumo ...
    1021             : !> \param non_monotonic ...
    1022             : !> \param eps_lanczos ...
    1023             : !> \param max_iter_lanczos ...
    1024             : !> \param iounit ...
    1025             : !> \author Jonathan Mullin
    1026             : ! **************************************************************************************************
    1027         120 :    SUBROUTINE density_matrix_tc2(matrix_p, matrix_ks, matrix_s_sqrt_inv, &
    1028             :                                  nelectron, threshold, e_homo, e_lumo, &
    1029             :                                  non_monotonic, eps_lanczos, max_iter_lanczos, iounit)
    1030             : 
    1031             :       TYPE(dbcsr_type), INTENT(INOUT)                    :: matrix_p
    1032             :       TYPE(dbcsr_type), INTENT(IN)                       :: matrix_ks, matrix_s_sqrt_inv
    1033             :       INTEGER, INTENT(IN)                                :: nelectron
    1034             :       REAL(KIND=dp), INTENT(IN)                          :: threshold
    1035             :       REAL(KIND=dp), INTENT(INOUT)                       :: e_homo, e_lumo
    1036             :       LOGICAL, INTENT(IN), OPTIONAL                      :: non_monotonic
    1037             :       REAL(KIND=dp), INTENT(IN)                          :: eps_lanczos
    1038             :       INTEGER, INTENT(IN)                                :: max_iter_lanczos
    1039             :       INTEGER, INTENT(IN), OPTIONAL                      :: iounit
    1040             : 
    1041             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'density_matrix_tc2'
    1042             :       INTEGER, PARAMETER                                 :: max_iter = 100
    1043             : 
    1044             :       INTEGER                                            :: handle, i, j, k, unit_nr
    1045             :       INTEGER(kind=int_8)                                :: flop1, flop2
    1046             :       LOGICAL                                            :: converged, do_non_monotonic
    1047             :       REAL(KIND=dp)                                      :: beta, betaB, eps_max, eps_min, gama, &
    1048             :                                                             max_eig, min_eig, occ_matrix, t1, t2, &
    1049             :                                                             trace_fx, trace_gx
    1050         120 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: alpha, lambda, nu, poly, wu, X, Y
    1051             :       TYPE(cp_logger_type), POINTER                      :: logger
    1052             :       TYPE(dbcsr_type)                                   :: matrix_tmp, matrix_x, matrix_xsq
    1053             : 
    1054         120 :       CALL timeset(routineN, handle)
    1055             : 
    1056         120 :       IF (PRESENT(iounit)) THEN
    1057         118 :          unit_nr = iounit
    1058             :       ELSE
    1059           2 :          logger => cp_get_default_logger()
    1060           2 :          IF (logger%para_env%is_source()) THEN
    1061           1 :             unit_nr = cp_logger_get_default_unit_nr(logger, local=.TRUE.)
    1062             :          ELSE
    1063           1 :             unit_nr = -1
    1064             :          END IF
    1065             :       END IF
    1066             : 
    1067         120 :       do_non_monotonic = .FALSE.
    1068         120 :       IF (PRESENT(non_monotonic)) do_non_monotonic = non_monotonic
    1069             : 
    1070             :       ! init X = (eps_n*I - H)/(eps_n - eps_0)  ... H* = S^-1/2*H*S^-1/2
    1071         120 :       CALL dbcsr_create(matrix_x, template=matrix_ks, matrix_type=dbcsr_type_no_symmetry)
    1072         120 :       CALL dbcsr_create(matrix_xsq, template=matrix_ks, matrix_type=dbcsr_type_no_symmetry)
    1073             : 
    1074             :       CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_s_sqrt_inv, matrix_ks, &
    1075         120 :                           0.0_dp, matrix_xsq, filter_eps=threshold)
    1076             :       CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_xsq, matrix_s_sqrt_inv, &
    1077         120 :                           0.0_dp, matrix_x, filter_eps=threshold)
    1078             : 
    1079         120 :       IF (unit_nr > 0) THEN
    1080           1 :          WRITE (unit_nr, '(T6,A,1X,F12.5)') "HOMO upper bound:       ", e_homo
    1081           1 :          WRITE (unit_nr, '(T6,A,1X,F12.5)') "LUMO lower bound:       ", e_lumo
    1082           1 :          WRITE (unit_nr, '(T6,A,1X,L12)') "Predicts a gap ?        ", ((e_lumo) - (e_homo)) > 0
    1083             :       END IF
    1084             : 
    1085             :       ! get largest/smallest eigenvalues for scaling
    1086             :       CALL arnoldi_extremal(matrix_x, max_eig, min_eig, max_iter=max_iter_lanczos, threshold=eps_lanczos, &
    1087         120 :                             converged=converged)
    1088         121 :       IF (unit_nr > 0) WRITE (unit_nr, '(T6,A,1X,2F12.5,1X,A,1X,L1)') "Est. extremal eigenvalues", &
    1089           2 :          min_eig, max_eig, " converged: ", converged
    1090             : 
    1091         120 :       eps_max = max_eig
    1092         120 :       eps_min = min_eig
    1093             : 
    1094             :       ! scale KS matrix
    1095         120 :       CALL dbcsr_scale(matrix_x, -1.0_dp)
    1096         120 :       CALL dbcsr_add_on_diag(matrix_x, eps_max)
    1097         120 :       CALL dbcsr_scale(matrix_x, 1/(eps_max - eps_min))
    1098             : 
    1099         120 :       CALL dbcsr_copy(matrix_xsq, matrix_x)
    1100             : 
    1101         120 :       CALL dbcsr_create(matrix_tmp, template=matrix_ks, matrix_type=dbcsr_type_no_symmetry)
    1102             : 
    1103         120 :       ALLOCATE (poly(max_iter))
    1104         120 :       ALLOCATE (nu(max_iter))
    1105         120 :       ALLOCATE (wu(max_iter))
    1106         120 :       ALLOCATE (alpha(max_iter))
    1107         120 :       ALLOCATE (X(4))
    1108         120 :       ALLOCATE (Y(4))
    1109         120 :       ALLOCATE (lambda(4))
    1110             : 
    1111             : ! Controls over the non_monotonic bounds, First if low gap, bias slightly
    1112         120 :       beta = (eps_max - ABS(e_lumo))/(eps_max - eps_min)
    1113         120 :       betaB = (eps_max + ABS(e_homo))/(eps_max - eps_min)
    1114             : 
    1115         120 :       IF ((beta - betaB) < 0.005_dp) THEN
    1116         120 :          beta = beta - 0.002_dp
    1117         120 :          betaB = betaB + 0.002_dp
    1118             :       END IF
    1119             : ! Check if input specifies to use monotonic bounds.
    1120         120 :       IF (.NOT. do_non_monotonic) THEN
    1121          26 :          beta = 0.0_dp
    1122          26 :          betaB = 1.0_dp
    1123             :       END IF
    1124             : ! initial SCF cycle has no reliable estimate of homo/lumo, force monotinic bounds.
    1125         120 :       IF (e_homo == 0.0_dp) THEN
    1126          76 :          beta = 0.0_dp
    1127          76 :          BetaB = 1.0_dp
    1128             :       END IF
    1129             : 
    1130             :       ! init to take true branch first
    1131         120 :       trace_fx = nelectron
    1132         120 :       trace_gx = 0
    1133             : 
    1134        2194 :       DO i = 1, max_iter
    1135        2194 :          t1 = m_walltime()
    1136        2194 :          flop1 = 0; flop2 = 0
    1137             : 
    1138        2194 :          IF (ABS(trace_fx - nelectron) <= ABS(trace_gx - nelectron)) THEN
    1139             : ! Xn+1 = (aX+ (1-a)I)^2
    1140        1110 :             poly(i) = 1.0_dp
    1141        1110 :             alpha(i) = 2.0_dp/(2.0_dp - beta)
    1142             : 
    1143        1110 :             CALL dbcsr_scale(matrix_x, alpha(i))
    1144        1110 :             CALL dbcsr_add_on_diag(matrix_x, 1.0_dp - alpha(i))
    1145             :             CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_x, matrix_x, &
    1146             :                                 0.0_dp, matrix_xsq, &
    1147        1110 :                                 filter_eps=threshold, flop=flop1)
    1148             : 
    1149             : !save X for control variables
    1150        1110 :             CALL dbcsr_copy(matrix_tmp, matrix_x)
    1151             : 
    1152        1110 :             CALL dbcsr_copy(matrix_x, matrix_xsq)
    1153             : 
    1154        1110 :             beta = (1.0_dp - alpha(i)) + alpha(i)*beta
    1155        1110 :             beta = beta*beta
    1156        1110 :             betaB = (1.0_dp - alpha(i)) + alpha(i)*betaB
    1157        1110 :             betaB = betaB*betaB
    1158             :          ELSE
    1159             : ! Xn+1 = 2aX-a^2*X^2
    1160        1084 :             poly(i) = 0.0_dp
    1161        1084 :             alpha(i) = 2.0_dp/(1.0_dp + betaB)
    1162             : 
    1163        1084 :             CALL dbcsr_scale(matrix_x, alpha(i))
    1164             :             CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_x, matrix_x, &
    1165             :                                 0.0_dp, matrix_xsq, &
    1166        1084 :                                 filter_eps=threshold, flop=flop1)
    1167             : 
    1168             : !save X for control variables
    1169        1084 :             CALL dbcsr_copy(matrix_tmp, matrix_x)
    1170             : !
    1171        1084 :             CALL dbcsr_add(matrix_x, matrix_xsq, 2.0_dp, -1.0_dp)
    1172             : 
    1173        1084 :             beta = alpha(i)*beta
    1174        1084 :             beta = 2.0_dp*beta - beta*beta
    1175        1084 :             betaB = alpha(i)*betaB
    1176        1084 :             betaB = 2.0_dp*betaB - betaB*betaB
    1177             : 
    1178             :          END IF
    1179        2194 :          occ_matrix = dbcsr_get_occupation(matrix_x)
    1180        2194 :          t2 = m_walltime()
    1181        2194 :          IF (unit_nr > 0) THEN
    1182             :             WRITE (unit_nr, &
    1183          18 :                    '(T6,A,I3,1X,F10.8,E12.3,F12.3,F13.3,E12.3)') "TC2 it ", &
    1184          18 :                i, occ_matrix, t2 - t1, &
    1185          36 :                (flop1 + flop2)/(1.0E6_dp*(t2 - t1)), threshold
    1186          18 :             CALL m_flush(unit_nr)
    1187             :          END IF
    1188             : 
    1189             : ! calculate control terms
    1190        2194 :          CALL dbcsr_trace(matrix_xsq, trace_fx)
    1191             : 
    1192             : ! intermediate use matrix_xsq compute X- X*X , temorarily use trace_gx
    1193        2194 :          CALL dbcsr_add(matrix_xsq, matrix_tmp, -1.0_dp, 1.0_dp)
    1194        2194 :          CALL dbcsr_trace(matrix_xsq, trace_gx)
    1195        2194 :          nu(i) = dbcsr_frobenius_norm(matrix_xsq)
    1196        2194 :          wu(i) = trace_gx
    1197             : 
    1198             : ! intermediate use matrix_xsq to compute = 2X - X*X
    1199        2194 :          CALL dbcsr_add(matrix_xsq, matrix_tmp, 1.0_dp, 1.0_dp)
    1200        2194 :          CALL dbcsr_trace(matrix_xsq, trace_gx)
    1201             : ! TC2 has quadratic convergence, using the frobeniums norm as an idempotency deviation test.
    1202        6582 :          IF (ABS(nu(i)) < (threshold)) EXIT
    1203             :       END DO
    1204             : 
    1205         120 :       occ_matrix = dbcsr_get_occupation(matrix_x)
    1206         120 :       IF (unit_nr > 0) WRITE (unit_nr, '(T6,A,I3,1X,1F10.8,1X,1F10.8)') 'Final TC2 iteration  ', i, occ_matrix, ABS(nu(i))
    1207             : 
    1208             :       ! output to matrix_p, P = inv(S)^0.5 X inv(S)^0.5
    1209             :       CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_x, matrix_s_sqrt_inv, &
    1210         120 :                           0.0_dp, matrix_tmp, filter_eps=threshold)
    1211             :       CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_s_sqrt_inv, matrix_tmp, &
    1212         120 :                           0.0_dp, matrix_p, filter_eps=threshold)
    1213             : 
    1214         120 :       CALL dbcsr_release(matrix_xsq)
    1215         120 :       CALL dbcsr_release(matrix_tmp)
    1216             : 
    1217             :       ! ALGO 3 from. SIAM DOI. 10.1137/130911585
    1218         120 :       X(1) = 1.0_dp
    1219         120 :       X(2) = 1.0_dp
    1220         120 :       X(3) = 0.0_dp
    1221         120 :       X(4) = 0.0_dp
    1222             :       gama = 6.0_dp - 4.0_dp*(SQRT(2.0_dp))
    1223         120 :       gama = gama - gama*gama
    1224        1214 :       DO WHILE (nu(i) < gama)
    1225             :          ! safeguard against negative root, is skipping correct?
    1226        1094 :          IF (wu(i) < 1.0e-14_dp) THEN
    1227          34 :             i = i - 1
    1228          34 :             CYCLE
    1229             :          END IF
    1230        1060 :          IF ((1.0_dp - 4.0_dp*nu(i)*nu(i)/wu(i)) < 0.0_dp) THEN
    1231           0 :             i = i - 1
    1232           0 :             CYCLE
    1233             :          END IF
    1234        1060 :          Y(1) = 0.5_dp*(1.0_dp - SQRT(1.0_dp - 4.0_dp*nu(i)*nu(i)/wu(i)))
    1235        1060 :          Y(2) = 0.5_dp*(1.0_dp - SQRT(1.0_dp - 4.0_dp*nu(i)))
    1236        1060 :          Y(3) = 0.5_dp*(1.0_dp + SQRT(1.0_dp - 4.0_dp*nu(i)))
    1237        1060 :          Y(4) = 0.5_dp*(1.0_dp + SQRT(1.0_dp - 4.0_dp*nu(i)*nu(i)/wu(i)))
    1238        5300 :          Y(:) = MIN(1.0_dp, MAX(0.0_dp, Y(:)))
    1239       16616 :          DO j = i, 1, -1
    1240       16616 :             IF (poly(j) == 1.0_dp) THEN
    1241       38890 :                DO k = 1, 4
    1242       31112 :                   Y(k) = SQRT(Y(k))
    1243       38890 :                   Y(k) = (Y(k) - 1.0_dp + alpha(j))/alpha(j)
    1244             :                END DO ! end K
    1245             :             ELSE
    1246       38890 :                DO k = 1, 4
    1247       31112 :                   Y(k) = 1.0_dp - SQRT(1.0_dp - Y(k))
    1248       38890 :                   Y(k) = Y(k)/alpha(j)
    1249             :                END DO ! end K
    1250             :             END IF ! end poly
    1251             :          END DO ! end j
    1252        1060 :          X(1) = MIN(X(1), Y(1))
    1253        1060 :          X(2) = MIN(X(2), Y(2))
    1254        1060 :          X(3) = MAX(X(3), Y(3))
    1255        1060 :          X(4) = MAX(X(4), Y(4))
    1256        1060 :          i = i - 1
    1257             :       END DO ! end i
    1258             : !   lambda 1,2,3,4 are:: out lumo, in lumo, in homo, out homo
    1259         600 :       DO k = 1, 4
    1260         600 :          lambda(k) = eps_max - (eps_max - eps_min)*X(k)
    1261             :       END DO ! end k
    1262             : ! END  ALGO 3 from. SIAM DOI. 10.1137/130911585
    1263         120 :       e_homo = lambda(4)
    1264         120 :       e_lumo = lambda(1)
    1265         120 :       IF (unit_nr > 0) WRITE (unit_nr, '(T6,A,3E12.4)') "outer homo/lumo/gap", e_homo, e_lumo, (e_lumo - e_homo)
    1266         120 :       IF (unit_nr > 0) WRITE (unit_nr, '(T6,A,3E12.4)') "inner homo/lumo/gap", lambda(3), lambda(2), (lambda(2) - lambda(3))
    1267             : 
    1268         120 :       DEALLOCATE (poly)
    1269         120 :       DEALLOCATE (nu)
    1270         120 :       DEALLOCATE (wu)
    1271         120 :       DEALLOCATE (alpha)
    1272         120 :       DEALLOCATE (X)
    1273         120 :       DEALLOCATE (Y)
    1274         120 :       DEALLOCATE (lambda)
    1275             : 
    1276         120 :       CALL dbcsr_release(matrix_x)
    1277         120 :       CALL timestop(handle)
    1278             : 
    1279         240 :    END SUBROUTINE density_matrix_tc2
    1280             : 
    1281             : ! **************************************************************************************************
    1282             : !> \brief compute the homo and lumo given a KS matrix and a density matrix in the orthonormalized basis
    1283             : !>        and the eps_min and eps_max, min and max eigenvalue of the ks matrix
    1284             : !> \param matrix_k ...
    1285             : !> \param matrix_p ...
    1286             : !> \param eps_min ...
    1287             : !> \param eps_max ...
    1288             : !> \param threshold ...
    1289             : !> \param max_iter_lanczos ...
    1290             : !> \param eps_lanczos ...
    1291             : !> \param homo ...
    1292             : !> \param lumo ...
    1293             : !> \param unit_nr ...
    1294             : !> \par History
    1295             : !>       2012.06 created [Florian Thoele]
    1296             : !> \author Florian Thoele
    1297             : ! **************************************************************************************************
    1298         132 :    SUBROUTINE compute_homo_lumo(matrix_k, matrix_p, eps_min, eps_max, threshold, max_iter_lanczos, eps_lanczos, homo, lumo, unit_nr)
    1299             :       TYPE(dbcsr_type)                                   :: matrix_k, matrix_p
    1300             :       REAL(KIND=dp)                                      :: eps_min, eps_max, threshold
    1301             :       INTEGER, INTENT(IN)                                :: max_iter_lanczos
    1302             :       REAL(KIND=dp), INTENT(IN)                          :: eps_lanczos
    1303             :       REAL(KIND=dp)                                      :: homo, lumo
    1304             :       INTEGER                                            :: unit_nr
    1305             : 
    1306             :       LOGICAL                                            :: converged
    1307             :       REAL(KIND=dp)                                      :: max_eig, min_eig, shift1, shift2
    1308             :       TYPE(dbcsr_type)                                   :: tmp1, tmp2, tmp3
    1309             : 
    1310             : ! temporary matrices used for HOMO/LUMO calculation
    1311             : 
    1312          44 :       CALL dbcsr_create(tmp1, template=matrix_k, matrix_type=dbcsr_type_no_symmetry)
    1313             : 
    1314          44 :       CALL dbcsr_create(tmp2, template=matrix_k, matrix_type=dbcsr_type_no_symmetry)
    1315             : 
    1316          44 :       CALL dbcsr_create(tmp3, template=matrix_k, matrix_type=dbcsr_type_no_symmetry)
    1317             : 
    1318          44 :       shift1 = -eps_min
    1319          44 :       shift2 = eps_max
    1320             : 
    1321             :       ! find largest ev of P*(K+shift*1), where shift is the neg. val. of the smallest ev of K
    1322          44 :       CALL dbcsr_copy(tmp2, matrix_k)
    1323          44 :       CALL dbcsr_add_on_diag(tmp2, shift1)
    1324             :       CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_p, tmp2, &
    1325          44 :                           0.0_dp, tmp1, filter_eps=threshold)
    1326             :       CALL arnoldi_extremal(tmp1, max_eig, min_eig, converged=converged, &
    1327          44 :                             threshold=eps_lanczos, max_iter=max_iter_lanczos)
    1328          44 :       homo = max_eig - shift1
    1329          44 :       IF (unit_nr > 0) THEN
    1330          10 :          WRITE (unit_nr, '(T6,A,1X,L12)') "Lanczos converged:      ", converged
    1331             :       END IF
    1332             : 
    1333             :       ! -(1-P)*(K-shift*1) = (1-P)*(shift*1 - K), where shift is the largest ev of K
    1334          44 :       CALL dbcsr_copy(tmp3, matrix_p)
    1335          44 :       CALL dbcsr_scale(tmp3, -1.0_dp)
    1336          44 :       CALL dbcsr_add_on_diag(tmp3, 1.0_dp) !tmp3 = 1-P
    1337          44 :       CALL dbcsr_copy(tmp2, matrix_k)
    1338          44 :       CALL dbcsr_add_on_diag(tmp2, -shift2)
    1339             :       CALL dbcsr_multiply("N", "N", -1.0_dp, tmp3, tmp2, &
    1340          44 :                           0.0_dp, tmp1, filter_eps=threshold)
    1341             :       CALL arnoldi_extremal(tmp1, max_eig, min_eig, converged=converged, &
    1342          44 :                             threshold=eps_lanczos, max_iter=max_iter_lanczos)
    1343          44 :       lumo = -max_eig + shift2
    1344             : 
    1345          44 :       IF (unit_nr > 0) THEN
    1346          10 :          WRITE (unit_nr, '(T6,A,1X,L12)') "Lanczos converged:      ", converged
    1347          10 :          WRITE (unit_nr, '(T6,A,1X,3F12.5)') 'HOMO/LUMO/gap', homo, lumo, lumo - homo
    1348             :       END IF
    1349          44 :       CALL dbcsr_release(tmp1)
    1350          44 :       CALL dbcsr_release(tmp2)
    1351          44 :       CALL dbcsr_release(tmp3)
    1352             : 
    1353          44 :    END SUBROUTINE compute_homo_lumo
    1354             : 
    1355             : ! **************************************************************************************************
    1356             : !> \brief ...
    1357             : !> \param x ...
    1358             : !> \param gamma_values ...
    1359             : !> \param i ...
    1360             : !> \return ...
    1361             : ! **************************************************************************************************
    1362      176088 :    FUNCTION evaluate_trs4_polynomial(x, gamma_values, i) RESULT(xr)
    1363             :       REAL(KIND=dp)                                      :: x
    1364             :       REAL(KIND=dp), DIMENSION(:)                        :: gamma_values
    1365             :       INTEGER                                            :: i
    1366             :       REAL(KIND=dp)                                      :: xr
    1367             : 
    1368             :       REAL(KIND=dp), PARAMETER                           :: gam_max = 6.0_dp, gam_min = 0.0_dp
    1369             : 
    1370             :       INTEGER                                            :: k
    1371             : 
    1372      176088 :       xr = x
    1373     1364784 :       DO k = 1, i
    1374     1364784 :          IF (gamma_values(k) > gam_max) THEN
    1375       18996 :             xr = 2*xr - xr**2
    1376     1169700 :          ELSE IF (gamma_values(k) < gam_min) THEN
    1377       62974 :             xr = xr**2
    1378             :          ELSE
    1379     1106726 :             xr = (xr*xr)*(4*xr - 3*xr*xr) + gamma_values(k)*xr*xr*((1 - xr)**2)
    1380             :          END IF
    1381             :       END DO
    1382      176088 :    END FUNCTION evaluate_trs4_polynomial
    1383             : 
    1384             : ! **************************************************************************************************
    1385             : !> \brief ...
    1386             : !> \param homo ...
    1387             : !> \param lumo ...
    1388             : !> \param threshold ...
    1389             : !> \return ...
    1390             : ! **************************************************************************************************
    1391         130 :    FUNCTION estimate_steps(homo, lumo, threshold) RESULT(steps)
    1392             :       REAL(KIND=dp)                                      :: homo, lumo, threshold
    1393             :       INTEGER                                            :: steps
    1394             : 
    1395             :       INTEGER                                            :: i
    1396             :       REAL(KIND=dp)                                      :: h, l, m
    1397             : 
    1398         130 :       l = lumo
    1399         130 :       h = homo
    1400             : 
    1401         926 :       DO i = 1, 200
    1402         926 :          IF (ABS(l) < threshold .AND. ABS(1 - h) < threshold) EXIT
    1403         796 :          m = 0.5_dp*(h + l)
    1404         926 :          IF (m > 0.5_dp) THEN
    1405         412 :             h = h**2
    1406         412 :             l = l**2
    1407             :          ELSE
    1408         384 :             h = 2*h - h**2
    1409         384 :             l = 2*l - l**2
    1410             :          END IF
    1411             :       END DO
    1412         130 :       steps = i - 1
    1413         130 :    END FUNCTION estimate_steps
    1414             : 
    1415             : END MODULE dm_ls_scf_methods

Generated by: LCOV version 1.15