LCOV - code coverage report
Current view: top level - src - dm_ls_scf_methods.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:71c3ab0) Lines: 93.4 % 543 507
Test Date: 2026-07-25 06:35:44 Functions: 100.0 % 11 11

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

Generated by: LCOV version 2.0-1