LCOV - code coverage report
Current view: top level - src - preconditioner_makes.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:b4bd748) Lines: 278 305 91.1 %
Date: 2025-03-09 07:56:22 Functions: 8 8 100.0 %

          Line data    Source code
       1             : !--------------------------------------------------------------------------------------------------!
       2             : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3             : !   Copyright 2000-2025 CP2K developers group <https://cp2k.org>                                   !
       4             : !                                                                                                  !
       5             : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6             : !--------------------------------------------------------------------------------------------------!
       7             : 
       8             : ! **************************************************************************************************
       9             : !> \brief computes preconditioners, and implements methods to apply them
      10             : !>      currently used in qs_ot
      11             : !> \par History
      12             : !>      - [UB] 2009-05-13 Adding stable approximate inverse (full and sparse)
      13             : !> \author Joost VandeVondele (09.2002)
      14             : ! **************************************************************************************************
      15             : MODULE preconditioner_makes
      16             :    USE arnoldi_api,                     ONLY: arnoldi_env_type,&
      17             :                                               arnoldi_ev,&
      18             :                                               deallocate_arnoldi_env,&
      19             :                                               get_selected_ritz_val,&
      20             :                                               get_selected_ritz_vector,&
      21             :                                               set_arnoldi_initial_vector,&
      22             :                                               setup_arnoldi_env
      23             :    USE cp_dbcsr_api,                    ONLY: &
      24             :         dbcsr_add, dbcsr_copy, dbcsr_create, dbcsr_get_info, dbcsr_multiply, dbcsr_p_type, &
      25             :         dbcsr_release, dbcsr_type, dbcsr_type_symmetric
      26             :    USE cp_dbcsr_contrib,                ONLY: dbcsr_add_on_diag
      27             :    USE cp_dbcsr_operations,             ONLY: copy_dbcsr_to_fm,&
      28             :                                               cp_dbcsr_m_by_n_from_template,&
      29             :                                               cp_dbcsr_sm_fm_multiply,&
      30             :                                               cp_fm_to_dbcsr_row_template
      31             :    USE cp_fm_basic_linalg,              ONLY: cp_fm_column_scale,&
      32             :                                               cp_fm_triangular_invert,&
      33             :                                               cp_fm_triangular_multiply,&
      34             :                                               cp_fm_uplo_to_full
      35             :    USE cp_fm_cholesky,                  ONLY: cp_fm_cholesky_decompose,&
      36             :                                               cp_fm_cholesky_reduce,&
      37             :                                               cp_fm_cholesky_restore
      38             :    USE cp_fm_diag,                      ONLY: choose_eigv_solver
      39             :    USE cp_fm_struct,                    ONLY: cp_fm_struct_create,&
      40             :                                               cp_fm_struct_release,&
      41             :                                               cp_fm_struct_type
      42             :    USE cp_fm_types,                     ONLY: cp_fm_create,&
      43             :                                               cp_fm_get_diag,&
      44             :                                               cp_fm_get_info,&
      45             :                                               cp_fm_release,&
      46             :                                               cp_fm_to_fm,&
      47             :                                               cp_fm_type
      48             :    USE input_constants,                 ONLY: &
      49             :         cholesky_inverse, cholesky_reduce, ot_precond_full_all, ot_precond_full_kinetic, &
      50             :         ot_precond_full_single, ot_precond_full_single_inverse, ot_precond_s_inverse, &
      51             :         ot_precond_solver_default, ot_precond_solver_inv_chol
      52             :    USE kinds,                           ONLY: dp
      53             :    USE parallel_gemm_api,               ONLY: parallel_gemm
      54             :    USE preconditioner_types,            ONLY: preconditioner_type
      55             : #include "./base/base_uses.f90"
      56             : 
      57             :    IMPLICIT NONE
      58             : 
      59             :    PRIVATE
      60             : 
      61             :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'preconditioner_makes'
      62             : 
      63             :    PUBLIC :: make_preconditioner_matrix
      64             : 
      65             : CONTAINS
      66             : 
      67             : ! **************************************************************************************************
      68             : !> \brief ...
      69             : !> \param preconditioner_env ...
      70             : !> \param matrix_h ...
      71             : !> \param matrix_s ...
      72             : !> \param matrix_t ...
      73             : !> \param mo_coeff ...
      74             : !> \param energy_homo ...
      75             : !> \param eigenvalues_ot ...
      76             : !> \param energy_gap ...
      77             : !> \param my_solver_type ...
      78             : ! **************************************************************************************************
      79        8449 :    SUBROUTINE make_preconditioner_matrix(preconditioner_env, matrix_h, matrix_s, matrix_t, mo_coeff, &
      80        8449 :                                          energy_homo, eigenvalues_ot, energy_gap, &
      81             :                                          my_solver_type)
      82             :       TYPE(preconditioner_type)                          :: preconditioner_env
      83             :       TYPE(dbcsr_type), POINTER                          :: matrix_h
      84             :       TYPE(dbcsr_type), OPTIONAL, POINTER                :: matrix_s, matrix_t
      85             :       TYPE(cp_fm_type), INTENT(IN)                       :: mo_coeff
      86             :       REAL(KIND=dp)                                      :: energy_homo
      87             :       REAL(KIND=dp), DIMENSION(:)                        :: eigenvalues_ot
      88             :       REAL(KIND=dp)                                      :: energy_gap
      89             :       INTEGER                                            :: my_solver_type
      90             : 
      91             :       INTEGER                                            :: precon_type
      92             : 
      93        8449 :       precon_type = preconditioner_env%in_use
      94          48 :       SELECT CASE (precon_type)
      95             :       CASE (ot_precond_full_single)
      96          48 :          IF (my_solver_type .NE. ot_precond_solver_default) &
      97           0 :             CPABORT("Only PRECOND_SOLVER DEFAULT for the moment")
      98          48 :          IF (PRESENT(matrix_s)) THEN
      99             :             CALL make_full_single(preconditioner_env, preconditioner_env%fm, &
     100          42 :                                   matrix_h, matrix_s, energy_homo, energy_gap)
     101             :          ELSE
     102             :             CALL make_full_single_ortho(preconditioner_env, preconditioner_env%fm, &
     103           6 :                                         matrix_h, energy_homo, energy_gap)
     104             :          END IF
     105             : 
     106             :       CASE (ot_precond_s_inverse)
     107          72 :          IF (my_solver_type .EQ. ot_precond_solver_default) my_solver_type = ot_precond_solver_inv_chol
     108          72 :          IF (.NOT. PRESENT(matrix_s)) &
     109           0 :             CPABORT("Type for S=1 not implemented")
     110          72 :          CALL make_full_s_inverse(preconditioner_env, matrix_s)
     111             : 
     112             :       CASE (ot_precond_full_kinetic)
     113        1289 :          IF (my_solver_type .EQ. ot_precond_solver_default) my_solver_type = ot_precond_solver_inv_chol
     114        1289 :          IF (.NOT. (PRESENT(matrix_s) .AND. PRESENT(matrix_t))) &
     115           0 :             CPABORT("Type for S=1 not implemented")
     116        1289 :          CALL make_full_kinetic(preconditioner_env, matrix_t, matrix_s, energy_gap)
     117             :       CASE (ot_precond_full_single_inverse)
     118        4030 :          IF (my_solver_type .EQ. ot_precond_solver_default) my_solver_type = ot_precond_solver_inv_chol
     119             :          CALL make_full_single_inverse(preconditioner_env, mo_coeff, matrix_h, energy_gap, &
     120        4030 :                                        matrix_s=matrix_s)
     121             :       CASE (ot_precond_full_all)
     122        3010 :          IF (my_solver_type .NE. ot_precond_solver_default) THEN
     123           0 :             CPABORT("Only PRECOND_SOLVER DEFAULT for the moment")
     124             :          END IF
     125        3010 :          IF (PRESENT(matrix_s)) THEN
     126             :             CALL make_full_all(preconditioner_env, mo_coeff, matrix_h, matrix_s, &
     127        2904 :                                eigenvalues_ot, energy_gap)
     128             :          ELSE
     129             :             CALL make_full_all_ortho(preconditioner_env, mo_coeff, matrix_h, &
     130         106 :                                      eigenvalues_ot, energy_gap)
     131             :          END IF
     132             : 
     133             :       CASE DEFAULT
     134        8449 :          CPABORT("Type not implemented")
     135             :       END SELECT
     136             : 
     137        8449 :    END SUBROUTINE make_preconditioner_matrix
     138             : 
     139             : ! **************************************************************************************************
     140             : !> \brief Simply takes the overlap matrix as preconditioner
     141             : !> \param preconditioner_env ...
     142             : !> \param matrix_s ...
     143             : ! **************************************************************************************************
     144          72 :    SUBROUTINE make_full_s_inverse(preconditioner_env, matrix_s)
     145             :       TYPE(preconditioner_type)                          :: preconditioner_env
     146             :       TYPE(dbcsr_type), POINTER                          :: matrix_s
     147             : 
     148             :       CHARACTER(len=*), PARAMETER :: routineN = 'make_full_s_inverse'
     149             : 
     150             :       INTEGER                                            :: handle
     151             : 
     152          72 :       CALL timeset(routineN, handle)
     153             : 
     154          72 :       CPASSERT(ASSOCIATED(matrix_s))
     155             : 
     156          72 :       IF (.NOT. ASSOCIATED(preconditioner_env%sparse_matrix)) THEN
     157          72 :          ALLOCATE (preconditioner_env%sparse_matrix)
     158             :       END IF
     159          72 :       CALL dbcsr_copy(preconditioner_env%sparse_matrix, matrix_s, name="full_kinetic")
     160             : 
     161          72 :       CALL timestop(handle)
     162             : 
     163          72 :    END SUBROUTINE make_full_s_inverse
     164             : 
     165             : ! **************************************************************************************************
     166             : !> \brief kinetic matrix+shift*overlap as preconditioner. Cheap but could
     167             : !>        be better
     168             : !> \param preconditioner_env ...
     169             : !> \param matrix_t ...
     170             : !> \param matrix_s ...
     171             : !> \param energy_gap ...
     172             : ! **************************************************************************************************
     173        1289 :    SUBROUTINE make_full_kinetic(preconditioner_env, matrix_t, matrix_s, &
     174             :                                 energy_gap)
     175             :       TYPE(preconditioner_type)                          :: preconditioner_env
     176             :       TYPE(dbcsr_type), POINTER                          :: matrix_t, matrix_s
     177             :       REAL(KIND=dp)                                      :: energy_gap
     178             : 
     179             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'make_full_kinetic'
     180             : 
     181             :       INTEGER                                            :: handle
     182             :       REAL(KIND=dp)                                      :: shift
     183             : 
     184        1289 :       CALL timeset(routineN, handle)
     185             : 
     186        1289 :       CPASSERT(ASSOCIATED(matrix_t))
     187        1289 :       CPASSERT(ASSOCIATED(matrix_s))
     188             : 
     189        1289 :       IF (.NOT. ASSOCIATED(preconditioner_env%sparse_matrix)) THEN
     190        1287 :          ALLOCATE (preconditioner_env%sparse_matrix)
     191             :       END IF
     192        1289 :       CALL dbcsr_copy(preconditioner_env%sparse_matrix, matrix_t, name="full_kinetic")
     193             : 
     194        1289 :       shift = MAX(0.0_dp, energy_gap)
     195             : 
     196             :       CALL dbcsr_add(preconditioner_env%sparse_matrix, matrix_s, &
     197        1289 :                      alpha_scalar=1.0_dp, beta_scalar=shift)
     198             : 
     199        1289 :       CALL timestop(handle)
     200             : 
     201        1289 :    END SUBROUTINE make_full_kinetic
     202             : 
     203             : ! **************************************************************************************************
     204             : !> \brief full_single_preconditioner
     205             : !> \param preconditioner_env ...
     206             : !> \param fm ...
     207             : !> \param matrix_h ...
     208             : !> \param matrix_s ...
     209             : !> \param energy_homo ...
     210             : !> \param energy_gap ...
     211             : ! **************************************************************************************************
     212          42 :    SUBROUTINE make_full_single(preconditioner_env, fm, matrix_h, matrix_s, &
     213             :                                energy_homo, energy_gap)
     214             :       TYPE(preconditioner_type)                          :: preconditioner_env
     215             :       TYPE(cp_fm_type), POINTER                          :: fm
     216             :       TYPE(dbcsr_type), POINTER                          :: matrix_h, matrix_s
     217             :       REAL(KIND=dp)                                      :: energy_homo, energy_gap
     218             : 
     219             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'make_full_single'
     220             : 
     221             :       INTEGER                                            :: handle, i, n
     222          42 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: evals
     223             :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct_tmp
     224             :       TYPE(cp_fm_type)                                   :: fm_h, fm_s
     225             : 
     226          42 :       CALL timeset(routineN, handle)
     227             : 
     228          42 :       NULLIFY (fm_struct_tmp, evals)
     229             : 
     230          42 :       IF (ASSOCIATED(fm)) THEN
     231           0 :          CALL cp_fm_release(fm)
     232           0 :          DEALLOCATE (fm)
     233             :          NULLIFY (fm)
     234             :       END IF
     235          42 :       CALL dbcsr_get_info(matrix_h, nfullrows_total=n)
     236         126 :       ALLOCATE (evals(n))
     237             : 
     238             :       CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=n, ncol_global=n, &
     239             :                                context=preconditioner_env%ctxt, &
     240          42 :                                para_env=preconditioner_env%para_env)
     241          42 :       ALLOCATE (fm)
     242          42 :       CALL cp_fm_create(fm, fm_struct_tmp, name="preconditioner")
     243          42 :       CALL cp_fm_create(fm_h, fm_struct_tmp, name="fm_h")
     244          42 :       CALL cp_fm_create(fm_s, fm_struct_tmp, name="fm_s")
     245          42 :       CALL cp_fm_struct_release(fm_struct_tmp)
     246             : 
     247          42 :       CALL copy_dbcsr_to_fm(matrix_h, fm_h)
     248          42 :       CALL copy_dbcsr_to_fm(matrix_s, fm_s)
     249          42 :       CALL cp_fm_cholesky_decompose(fm_s)
     250             : 
     251          42 :       SELECT CASE (preconditioner_env%cholesky_use)
     252             :       CASE (cholesky_inverse)
     253             : ! if cho inverse
     254           0 :          CALL cp_fm_triangular_invert(fm_s)
     255           0 :          CALL cp_fm_uplo_to_full(fm_h, fm)
     256             : 
     257             :          CALL cp_fm_triangular_multiply(fm_s, fm_h, side="R", transpose_tr=.FALSE., &
     258           0 :                                         invert_tr=.FALSE., uplo_tr="U", n_rows=n, n_cols=n, alpha=1.0_dp)
     259             :          CALL cp_fm_triangular_multiply(fm_s, fm_h, side="L", transpose_tr=.TRUE., &
     260           0 :                                         invert_tr=.FALSE., uplo_tr="U", n_rows=n, n_cols=n, alpha=1.0_dp)
     261             :       CASE (cholesky_reduce)
     262          42 :          CALL cp_fm_cholesky_reduce(fm_h, fm_s)
     263             :       CASE DEFAULT
     264          42 :          CPABORT("cholesky type not implemented")
     265             :       END SELECT
     266             : 
     267          42 :       CALL choose_eigv_solver(fm_h, fm, evals)
     268             : 
     269          42 :       SELECT CASE (preconditioner_env%cholesky_use)
     270             :       CASE (cholesky_inverse)
     271             :          CALL cp_fm_triangular_multiply(fm_s, fm, side="L", transpose_tr=.FALSE., &
     272           0 :                                         invert_tr=.FALSE., uplo_tr="U", n_rows=n, n_cols=n, alpha=1.0_dp)
     273           0 :          DO i = 1, n
     274           0 :             evals(i) = 1.0_dp/MAX(evals(i) - energy_homo, energy_gap)
     275             :          END DO
     276           0 :          CALL cp_fm_to_fm(fm, fm_h)
     277             :       CASE (cholesky_reduce)
     278          42 :          CALL cp_fm_cholesky_restore(fm, n, fm_s, fm_h, "SOLVE")
     279         678 :          DO i = 1, n
     280         678 :             evals(i) = 1.0_dp/MAX(evals(i) - energy_homo, energy_gap)
     281             :          END DO
     282          84 :          CALL cp_fm_to_fm(fm_h, fm)
     283             :       END SELECT
     284             : 
     285          42 :       CALL cp_fm_column_scale(fm, evals)
     286          42 :       CALL parallel_gemm('N', 'T', n, n, n, 1.0_dp, fm, fm_h, 0.0_dp, fm_s)
     287          42 :       CALL cp_fm_to_fm(fm_s, fm)
     288             : 
     289          42 :       DEALLOCATE (evals)
     290          42 :       CALL cp_fm_release(fm_h)
     291          42 :       CALL cp_fm_release(fm_s)
     292             : 
     293          42 :       CALL timestop(handle)
     294             : 
     295         126 :    END SUBROUTINE make_full_single
     296             : 
     297             : ! **************************************************************************************************
     298             : !> \brief full single in the orthonormal basis
     299             : !> \param preconditioner_env ...
     300             : !> \param fm ...
     301             : !> \param matrix_h ...
     302             : !> \param energy_homo ...
     303             : !> \param energy_gap ...
     304             : ! **************************************************************************************************
     305           6 :    SUBROUTINE make_full_single_ortho(preconditioner_env, fm, matrix_h, &
     306             :                                      energy_homo, energy_gap)
     307             :       TYPE(preconditioner_type)                          :: preconditioner_env
     308             :       TYPE(cp_fm_type), POINTER                          :: fm
     309             :       TYPE(dbcsr_type), POINTER                          :: matrix_h
     310             :       REAL(KIND=dp)                                      :: energy_homo, energy_gap
     311             : 
     312             :       CHARACTER(len=*), PARAMETER :: routineN = 'make_full_single_ortho'
     313             : 
     314             :       INTEGER                                            :: handle, i, n
     315           6 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: evals
     316             :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct_tmp
     317             :       TYPE(cp_fm_type)                                   :: fm_h, fm_s
     318             : 
     319           6 :       CALL timeset(routineN, handle)
     320           6 :       NULLIFY (fm_struct_tmp, evals)
     321             : 
     322           6 :       IF (ASSOCIATED(fm)) THEN
     323           0 :          CALL cp_fm_release(fm)
     324           0 :          DEALLOCATE (fm)
     325             :          NULLIFY (fm)
     326             :       END IF
     327           6 :       CALL dbcsr_get_info(matrix_h, nfullrows_total=n)
     328          18 :       ALLOCATE (evals(n))
     329             : 
     330             :       CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=n, ncol_global=n, &
     331             :                                context=preconditioner_env%ctxt, &
     332           6 :                                para_env=preconditioner_env%para_env)
     333           6 :       ALLOCATE (fm)
     334           6 :       CALL cp_fm_create(fm, fm_struct_tmp, name="preconditioner")
     335           6 :       CALL cp_fm_create(fm_h, fm_struct_tmp, name="fm_h")
     336           6 :       CALL cp_fm_create(fm_s, fm_struct_tmp, name="fm_s")
     337           6 :       CALL cp_fm_struct_release(fm_struct_tmp)
     338             : 
     339           6 :       CALL copy_dbcsr_to_fm(matrix_h, fm_h)
     340             : 
     341           6 :       CALL choose_eigv_solver(fm_h, fm, evals)
     342         282 :       DO i = 1, n
     343         282 :          evals(i) = 1.0_dp/MAX(evals(i) - energy_homo, energy_gap)
     344             :       END DO
     345           6 :       CALL cp_fm_to_fm(fm, fm_h)
     346           6 :       CALL cp_fm_column_scale(fm, evals)
     347           6 :       CALL parallel_gemm('N', 'T', n, n, n, 1.0_dp, fm, fm_h, 0.0_dp, fm_s)
     348           6 :       CALL cp_fm_to_fm(fm_s, fm)
     349             : 
     350           6 :       DEALLOCATE (evals)
     351           6 :       CALL cp_fm_release(fm_h)
     352           6 :       CALL cp_fm_release(fm_s)
     353             : 
     354           6 :       CALL timestop(handle)
     355             : 
     356          18 :    END SUBROUTINE make_full_single_ortho
     357             : 
     358             : ! **************************************************************************************************
     359             : !> \brief generates a state by state preconditioner based on the full hamiltonian matrix
     360             : !> \param preconditioner_env ...
     361             : !> \param matrix_c0 ...
     362             : !> \param matrix_h ...
     363             : !> \param matrix_s ...
     364             : !> \param c0_evals ...
     365             : !> \param energy_gap should be a slight underestimate of the physical energy gap for almost all systems
     366             : !>      the c0 are already ritz states of (h,s)
     367             : !> \par History
     368             : !>      10.2006 made more stable [Joost VandeVondele]
     369             : !> \note
     370             : !>      includes error estimate on the hamiltonian matrix to result in a stable preconditioner
     371             : !>      a preconditioner for each eigenstate i is generated by keeping the factorized form
     372             : !>      U diag( something i ) U^T. It is important to only precondition in the subspace orthogonal to c0.
     373             : !>      not only is it the only part that matters, it also simplifies the computation of
     374             : !>      the lagrangian multipliers in the OT minimization  (i.e. if the c0 here is different
     375             : !>      from the c0 used in the OT setup, there will be a bug).
     376             : ! **************************************************************************************************
     377        2904 :    SUBROUTINE make_full_all(preconditioner_env, matrix_c0, matrix_h, matrix_s, c0_evals, energy_gap)
     378             :       TYPE(preconditioner_type)                          :: preconditioner_env
     379             :       TYPE(cp_fm_type), INTENT(IN)                       :: matrix_c0
     380             :       TYPE(dbcsr_type), POINTER                          :: matrix_h, matrix_s
     381             :       REAL(KIND=dp), DIMENSION(:)                        :: c0_evals
     382             :       REAL(KIND=dp)                                      :: energy_gap
     383             : 
     384             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'make_full_all'
     385             :       REAL(KIND=dp), PARAMETER                           :: fudge_factor = 0.25_dp, &
     386             :                                                             lambda_base = 10.0_dp
     387             : 
     388             :       INTEGER                                            :: handle, k, n
     389             :       REAL(KIND=dp)                                      :: error_estimate, lambda
     390        2904 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: diag, norms, shifted_evals
     391             :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct_tmp
     392             :       TYPE(cp_fm_type)                                   :: matrix_hc0, matrix_left, matrix_s1, &
     393             :                                                             matrix_s2, matrix_sc0, matrix_shc0, &
     394             :                                                             matrix_tmp, ortho
     395             :       TYPE(cp_fm_type), POINTER                          :: matrix_pre
     396             : 
     397        2904 :       CALL timeset(routineN, handle)
     398             : 
     399        2904 :       IF (ASSOCIATED(preconditioner_env%fm)) THEN
     400           0 :          CALL cp_fm_release(preconditioner_env%fm)
     401           0 :          DEALLOCATE (preconditioner_env%fm)
     402             :          NULLIFY (preconditioner_env%fm)
     403             :       END IF
     404        2904 :       CALL cp_fm_get_info(matrix_c0, nrow_global=n, ncol_global=k)
     405             :       CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=n, ncol_global=n, &
     406             :                                context=preconditioner_env%ctxt, &
     407        2904 :                                para_env=preconditioner_env%para_env)
     408        2904 :       ALLOCATE (preconditioner_env%fm)
     409        2904 :       CALL cp_fm_create(preconditioner_env%fm, fm_struct_tmp, name="preconditioner_env%fm")
     410        2904 :       CALL cp_fm_create(ortho, fm_struct_tmp, name="ortho")
     411        2904 :       CALL cp_fm_create(matrix_tmp, fm_struct_tmp, name="matrix_tmp")
     412        2904 :       CALL cp_fm_struct_release(fm_struct_tmp)
     413        8712 :       ALLOCATE (preconditioner_env%full_evals(n))
     414        8610 :       ALLOCATE (preconditioner_env%occ_evals(k))
     415             : 
     416             :       ! 0) cholesky decompose the overlap matrix, if this fails the basis is singular,
     417             :       !    more than EPS_DEFAULT
     418        2904 :       CALL copy_dbcsr_to_fm(matrix_s, ortho)
     419        2904 :       CALL cp_fm_cholesky_decompose(ortho)
     420             : ! if cho inverse
     421        2904 :       IF (preconditioner_env%cholesky_use == cholesky_inverse) THEN
     422           0 :          CALL cp_fm_triangular_invert(ortho)
     423             :       END IF
     424             :       ! 1) Construct a new H matrix, which has the current C0 as eigenvectors,
     425             :       !    possibly shifted by an amount lambda,
     426             :       !    and the same spectrum as the original H matrix in the space orthogonal to the C0
     427             :       !    with P=C0 C0 ^ T
     428             :       !    (1 - PS)^T H (1-PS) + (PS)^T (H - lambda S ) (PS)
     429             :       !    we exploit that the C0 are already the ritz states of H
     430        2904 :       CALL cp_fm_create(matrix_sc0, matrix_c0%matrix_struct, name="sc0")
     431        2904 :       CALL cp_dbcsr_sm_fm_multiply(matrix_s, matrix_c0, matrix_sc0, k)
     432        2904 :       CALL cp_fm_create(matrix_hc0, matrix_c0%matrix_struct, name="hc0")
     433        2904 :       CALL cp_dbcsr_sm_fm_multiply(matrix_h, matrix_c0, matrix_hc0, k)
     434             : 
     435             :       ! An aside, try to estimate the error on the ritz values, we'll need it later on
     436        2904 :       CALL cp_fm_create(matrix_shc0, matrix_c0%matrix_struct, name="shc0")
     437             : 
     438        2904 :       SELECT CASE (preconditioner_env%cholesky_use)
     439             :       CASE (cholesky_inverse)
     440             : ! if cho inverse
     441           0 :          CALL cp_fm_to_fm(matrix_hc0, matrix_shc0)
     442             :          CALL cp_fm_triangular_multiply(ortho, matrix_shc0, side="L", transpose_tr=.TRUE., &
     443           0 :                                         invert_tr=.FALSE., uplo_tr="U", n_rows=n, n_cols=k, alpha=1.0_dp)
     444             :       CASE (cholesky_reduce)
     445        2904 :          CALL cp_fm_cholesky_restore(matrix_hc0, k, ortho, matrix_shc0, "SOLVE", transa="T")
     446             :       CASE DEFAULT
     447        2904 :          CPABORT("cholesky type not implemented")
     448             :       END SELECT
     449             :       CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=k, ncol_global=k, &
     450             :                                context=preconditioner_env%ctxt, &
     451        2904 :                                para_env=preconditioner_env%para_env)
     452        2904 :       CALL cp_fm_create(matrix_s1, fm_struct_tmp, name="matrix_s1")
     453        2904 :       CALL cp_fm_struct_release(fm_struct_tmp)
     454             :       ! since we only use diagonal elements this is a bit of a waste
     455        2904 :       CALL parallel_gemm('T', 'N', k, k, n, 1.0_dp, matrix_shc0, matrix_shc0, 0.0_dp, matrix_s1)
     456        5706 :       ALLOCATE (diag(k))
     457        2904 :       CALL cp_fm_get_diag(matrix_s1, diag)
     458       18104 :       error_estimate = MAXVAL(SQRT(ABS(diag - c0_evals**2)))
     459        2904 :       DEALLOCATE (diag)
     460        2904 :       CALL cp_fm_release(matrix_s1)
     461        2904 :       CALL cp_fm_release(matrix_shc0)
     462             :       ! we'll only use the energy gap, if our estimate of the error on the eigenvalues
     463             :       ! is small enough. A large error combined with a small energy gap would otherwise lead to
     464             :       ! an aggressive but bad preconditioner. Only when the error is small (MD), we can precondition
     465             :       ! aggressively
     466        2904 :       preconditioner_env%energy_gap = MAX(energy_gap, error_estimate*fudge_factor)
     467        2904 :       CALL copy_dbcsr_to_fm(matrix_h, matrix_tmp)
     468        2904 :       matrix_pre => preconditioner_env%fm
     469        2904 :       CALL cp_fm_uplo_to_full(matrix_tmp, matrix_pre)
     470             :       ! tmp = H ( 1 - PS )
     471        2904 :       CALL parallel_gemm('N', 'T', n, n, k, -1.0_dp, matrix_hc0, matrix_sc0, 1.0_dp, matrix_tmp)
     472             : 
     473             :       CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=k, ncol_global=n, &
     474             :                                context=preconditioner_env%ctxt, &
     475        2904 :                                para_env=preconditioner_env%para_env)
     476        2904 :       CALL cp_fm_create(matrix_left, fm_struct_tmp, name="matrix_left")
     477        2904 :       CALL cp_fm_struct_release(fm_struct_tmp)
     478        2904 :       CALL parallel_gemm('T', 'N', k, n, n, 1.0_dp, matrix_c0, matrix_tmp, 0.0_dp, matrix_left)
     479             :       ! tmp = (1 - PS)^T H (1-PS)
     480        2904 :       CALL parallel_gemm('N', 'N', n, n, k, -1.0_dp, matrix_sc0, matrix_left, 1.0_dp, matrix_tmp)
     481        2904 :       CALL cp_fm_release(matrix_left)
     482             : 
     483        5706 :       ALLOCATE (shifted_evals(k))
     484        2904 :       lambda = lambda_base + error_estimate
     485       15200 :       shifted_evals = c0_evals - lambda
     486        2904 :       CALL cp_fm_to_fm(matrix_sc0, matrix_hc0)
     487        2904 :       CALL cp_fm_column_scale(matrix_hc0, shifted_evals)
     488        2904 :       CALL parallel_gemm('N', 'T', n, n, k, 1.0_dp, matrix_hc0, matrix_sc0, 1.0_dp, matrix_tmp)
     489             : 
     490             :       ! 2) diagonalize this operator
     491        2904 :       SELECT CASE (preconditioner_env%cholesky_use)
     492             :       CASE (cholesky_inverse)
     493             :          CALL cp_fm_triangular_multiply(ortho, matrix_tmp, side="R", transpose_tr=.FALSE., &
     494           0 :                                         invert_tr=.FALSE., uplo_tr="U", n_rows=n, n_cols=n, alpha=1.0_dp)
     495             :          CALL cp_fm_triangular_multiply(ortho, matrix_tmp, side="L", transpose_tr=.TRUE., &
     496           0 :                                         invert_tr=.FALSE., uplo_tr="U", n_rows=n, n_cols=n, alpha=1.0_dp)
     497             :       CASE (cholesky_reduce)
     498        2904 :          CALL cp_fm_cholesky_reduce(matrix_tmp, ortho)
     499             :       END SELECT
     500        2904 :       CALL choose_eigv_solver(matrix_tmp, matrix_pre, preconditioner_env%full_evals)
     501        2904 :       SELECT CASE (preconditioner_env%cholesky_use)
     502             :       CASE (cholesky_inverse)
     503             :          CALL cp_fm_triangular_multiply(ortho, matrix_pre, side="L", transpose_tr=.FALSE., &
     504           0 :                                         invert_tr=.FALSE., uplo_tr="U", n_rows=n, n_cols=n, alpha=1.0_dp)
     505           0 :          CALL cp_fm_to_fm(matrix_pre, matrix_tmp)
     506             :       CASE (cholesky_reduce)
     507        2904 :          CALL cp_fm_cholesky_restore(matrix_pre, n, ortho, matrix_tmp, "SOLVE")
     508        5808 :          CALL cp_fm_to_fm(matrix_tmp, matrix_pre)
     509             :       END SELECT
     510             : 
     511             :       ! test that the subspace remained conserved
     512             :       IF (.FALSE.) THEN
     513             :          CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=k, ncol_global=k, &
     514             :                                   context=preconditioner_env%ctxt, &
     515             :                                   para_env=preconditioner_env%para_env)
     516             :          CALL cp_fm_create(matrix_s1, fm_struct_tmp, name="matrix_s1")
     517             :          CALL cp_fm_create(matrix_s2, fm_struct_tmp, name="matrix_s2")
     518             :          CALL cp_fm_struct_release(fm_struct_tmp)
     519             :          ALLOCATE (norms(k))
     520             :          CALL parallel_gemm('T', 'N', k, k, n, 1.0_dp, matrix_sc0, matrix_tmp, 0.0_dp, matrix_s1)
     521             :          CALL choose_eigv_solver(matrix_s1, matrix_s2, norms)
     522             :          WRITE (*, *) "matrix norm deviation (should be close to zero): ", MAXVAL(ABS(ABS(norms) - 1.0_dp))
     523             :          DEALLOCATE (norms)
     524             :          CALL cp_fm_release(matrix_s1)
     525             :          CALL cp_fm_release(matrix_s2)
     526             :       END IF
     527             : 
     528             :       ! 3) replace the lowest k evals and evecs with what they should be
     529       15200 :       preconditioner_env%occ_evals = c0_evals
     530             :       ! notice, this choice causes the preconditioner to be constant when applied to sc0 (see apply_full_all)
     531       15200 :       preconditioner_env%full_evals(1:k) = c0_evals
     532        2904 :       CALL cp_fm_to_fm(matrix_c0, matrix_pre, k, 1, 1)
     533             : 
     534        2904 :       CALL cp_fm_release(matrix_sc0)
     535        2904 :       CALL cp_fm_release(matrix_hc0)
     536        2904 :       CALL cp_fm_release(ortho)
     537        2904 :       CALL cp_fm_release(matrix_tmp)
     538        2904 :       DEALLOCATE (shifted_evals)
     539        2904 :       CALL timestop(handle)
     540             : 
     541       23232 :    END SUBROUTINE make_full_all
     542             : 
     543             : ! **************************************************************************************************
     544             : !> \brief full all in the orthonormal basis
     545             : !> \param preconditioner_env ...
     546             : !> \param matrix_c0 ...
     547             : !> \param matrix_h ...
     548             : !> \param c0_evals ...
     549             : !> \param energy_gap ...
     550             : ! **************************************************************************************************
     551         106 :    SUBROUTINE make_full_all_ortho(preconditioner_env, matrix_c0, matrix_h, c0_evals, energy_gap)
     552             : 
     553             :       TYPE(preconditioner_type)                          :: preconditioner_env
     554             :       TYPE(cp_fm_type), INTENT(IN)                       :: matrix_c0
     555             :       TYPE(dbcsr_type), POINTER                          :: matrix_h
     556             :       REAL(KIND=dp), DIMENSION(:)                        :: c0_evals
     557             :       REAL(KIND=dp)                                      :: energy_gap
     558             : 
     559             :       CHARACTER(len=*), PARAMETER :: routineN = 'make_full_all_ortho'
     560             :       REAL(KIND=dp), PARAMETER                           :: fudge_factor = 0.25_dp, &
     561             :                                                             lambda_base = 10.0_dp
     562             : 
     563             :       INTEGER                                            :: handle, k, n
     564             :       REAL(KIND=dp)                                      :: error_estimate, lambda
     565         106 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: diag, norms, shifted_evals
     566             :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct_tmp
     567             :       TYPE(cp_fm_type)                                   :: matrix_hc0, matrix_left, matrix_s1, &
     568             :                                                             matrix_s2, matrix_sc0, matrix_tmp
     569             :       TYPE(cp_fm_type), POINTER                          :: matrix_pre
     570             : 
     571         106 :       CALL timeset(routineN, handle)
     572             : 
     573         106 :       IF (ASSOCIATED(preconditioner_env%fm)) THEN
     574           0 :          CALL cp_fm_release(preconditioner_env%fm)
     575           0 :          DEALLOCATE (preconditioner_env%fm)
     576             :          NULLIFY (preconditioner_env%fm)
     577             :       END IF
     578         106 :       CALL cp_fm_get_info(matrix_c0, nrow_global=n, ncol_global=k)
     579             :       CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=n, ncol_global=n, &
     580             :                                context=preconditioner_env%ctxt, &
     581         106 :                                para_env=preconditioner_env%para_env)
     582         106 :       ALLOCATE (preconditioner_env%fm)
     583         106 :       CALL cp_fm_create(preconditioner_env%fm, fm_struct_tmp, name="preconditioner_env%fm")
     584         106 :       CALL cp_fm_create(matrix_tmp, fm_struct_tmp, name="matrix_tmp")
     585         106 :       CALL cp_fm_struct_release(fm_struct_tmp)
     586         318 :       ALLOCATE (preconditioner_env%full_evals(n))
     587         318 :       ALLOCATE (preconditioner_env%occ_evals(k))
     588             : 
     589             :       ! 1) Construct a new H matrix, which has the current C0 as eigenvectors,
     590             :       !    possibly shifted by an amount lambda,
     591             :       !    and the same spectrum as the original H matrix in the space orthogonal to the C0
     592             :       !    with P=C0 C0 ^ T
     593             :       !    (1 - PS)^T H (1-PS) + (PS)^T (H - lambda S ) (PS)
     594             :       !    we exploit that the C0 are already the ritz states of H
     595         106 :       CALL cp_fm_create(matrix_sc0, matrix_c0%matrix_struct, name="sc0")
     596         106 :       CALL cp_fm_to_fm(matrix_c0, matrix_sc0)
     597         106 :       CALL cp_fm_create(matrix_hc0, matrix_c0%matrix_struct, name="hc0")
     598         106 :       CALL cp_dbcsr_sm_fm_multiply(matrix_h, matrix_c0, matrix_hc0, k)
     599             : 
     600             :       ! An aside, try to estimate the error on the ritz values, we'll need it later on
     601             :       CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=k, ncol_global=k, &
     602             :                                context=preconditioner_env%ctxt, &
     603         106 :                                para_env=preconditioner_env%para_env)
     604         106 :       CALL cp_fm_create(matrix_s1, fm_struct_tmp, name="matrix_s1")
     605         106 :       CALL cp_fm_struct_release(fm_struct_tmp)
     606             :       ! since we only use diagonal elements this is a bit of a waste
     607         106 :       CALL parallel_gemm('T', 'N', k, k, n, 1.0_dp, matrix_hc0, matrix_hc0, 0.0_dp, matrix_s1)
     608         212 :       ALLOCATE (diag(k))
     609         106 :       CALL cp_fm_get_diag(matrix_s1, diag)
     610        1262 :       error_estimate = MAXVAL(SQRT(ABS(diag - c0_evals**2)))
     611         106 :       DEALLOCATE (diag)
     612         106 :       CALL cp_fm_release(matrix_s1)
     613             :       ! we'll only use the energy gap, if our estimate of the error on the eigenvalues
     614             :       ! is small enough. A large error combined with a small energy gap would otherwise lead to
     615             :       ! an aggressive but bad preconditioner. Only when the error is small (MD), we can precondition
     616             :       ! aggressively
     617         106 :       preconditioner_env%energy_gap = MAX(energy_gap, error_estimate*fudge_factor)
     618             : 
     619         106 :       matrix_pre => preconditioner_env%fm
     620         106 :       CALL copy_dbcsr_to_fm(matrix_h, matrix_tmp)
     621         106 :       CALL cp_fm_uplo_to_full(matrix_tmp, matrix_pre)
     622             :       ! tmp = H ( 1 - PS )
     623         106 :       CALL parallel_gemm('N', 'T', n, n, k, -1.0_dp, matrix_hc0, matrix_sc0, 1.0_dp, matrix_tmp)
     624             : 
     625             :       CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=k, ncol_global=n, &
     626             :                                context=preconditioner_env%ctxt, &
     627         106 :                                para_env=preconditioner_env%para_env)
     628         106 :       CALL cp_fm_create(matrix_left, fm_struct_tmp, name="matrix_left")
     629         106 :       CALL cp_fm_struct_release(fm_struct_tmp)
     630         106 :       CALL parallel_gemm('T', 'N', k, n, n, 1.0_dp, matrix_c0, matrix_tmp, 0.0_dp, matrix_left)
     631             :       ! tmp = (1 - PS)^T H (1-PS)
     632         106 :       CALL parallel_gemm('N', 'N', n, n, k, -1.0_dp, matrix_sc0, matrix_left, 1.0_dp, matrix_tmp)
     633         106 :       CALL cp_fm_release(matrix_left)
     634             : 
     635         212 :       ALLOCATE (shifted_evals(k))
     636         106 :       lambda = lambda_base + error_estimate
     637        1156 :       shifted_evals = c0_evals - lambda
     638         106 :       CALL cp_fm_to_fm(matrix_sc0, matrix_hc0)
     639         106 :       CALL cp_fm_column_scale(matrix_hc0, shifted_evals)
     640         106 :       CALL parallel_gemm('N', 'T', n, n, k, 1.0_dp, matrix_hc0, matrix_sc0, 1.0_dp, matrix_tmp)
     641             : 
     642             :       ! 2) diagonalize this operator
     643         106 :       CALL choose_eigv_solver(matrix_tmp, matrix_pre, preconditioner_env%full_evals)
     644             : 
     645             :       ! test that the subspace remained conserved
     646             :       IF (.FALSE.) THEN
     647             :          CALL cp_fm_to_fm(matrix_pre, matrix_tmp)
     648             :          CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=k, ncol_global=k, &
     649             :                                   context=preconditioner_env%ctxt, &
     650             :                                   para_env=preconditioner_env%para_env)
     651             :          CALL cp_fm_create(matrix_s1, fm_struct_tmp, name="matrix_s1")
     652             :          CALL cp_fm_create(matrix_s2, fm_struct_tmp, name="matrix_s2")
     653             :          CALL cp_fm_struct_release(fm_struct_tmp)
     654             :          ALLOCATE (norms(k))
     655             :          CALL parallel_gemm('T', 'N', k, k, n, 1.0_dp, matrix_sc0, matrix_tmp, 0.0_dp, matrix_s1)
     656             :          CALL choose_eigv_solver(matrix_s1, matrix_s2, norms)
     657             : 
     658             :          WRITE (*, *) "matrix norm deviation (should be close to zero): ", MAXVAL(ABS(ABS(norms) - 1.0_dp))
     659             :          DEALLOCATE (norms)
     660             :          CALL cp_fm_release(matrix_s1)
     661             :          CALL cp_fm_release(matrix_s2)
     662             :       END IF
     663             : 
     664             :       ! 3) replace the lowest k evals and evecs with what they should be
     665        1156 :       preconditioner_env%occ_evals = c0_evals
     666             :       ! notice, this choice causes the preconditioner to be constant when applied to sc0 (see apply_full_all)
     667        1156 :       preconditioner_env%full_evals(1:k) = c0_evals
     668         106 :       CALL cp_fm_to_fm(matrix_c0, matrix_pre, k, 1, 1)
     669             : 
     670         106 :       CALL cp_fm_release(matrix_sc0)
     671         106 :       CALL cp_fm_release(matrix_hc0)
     672         106 :       CALL cp_fm_release(matrix_tmp)
     673         106 :       DEALLOCATE (shifted_evals)
     674             : 
     675         106 :       CALL timestop(handle)
     676             : 
     677         742 :    END SUBROUTINE make_full_all_ortho
     678             : 
     679             : ! **************************************************************************************************
     680             : !> \brief generates a preconditioner matrix H-lambda S+(SC)(2.0*CT*H*C+delta)(SC)^T
     681             : !>        for later inversion.
     682             : !>        H is the Kohn Sham matrix
     683             : !>        lambda*S shifts the spectrum of the generalized form up by lambda
     684             : !>        the last term only shifts the occupied space (reversing them in energy order)
     685             : !>        This form is implicitly multiplied from both sides by S^0.5
     686             : !>        This ensures we precondition the correct quantity
     687             : !>        Before this reads S^-0.5 H S^-0.5 + lambda + (S^0.5 C)shifts(S^0.5 C)T
     688             : !>        which might be a bit more obvious
     689             : !>        Replaced the old full_single_inverse at revision 14616
     690             : !> \param preconditioner_env the preconditioner env
     691             : !> \param matrix_c0 the MO coefficient matrix (fm)
     692             : !> \param matrix_h Kohn-Sham matrix (dbcsr)
     693             : !> \param energy_gap an additional shift in lambda=-E_homo+energy_gap
     694             : !> \param matrix_s the overlap matrix if not orthonormal (dbcsr, optional)
     695             : ! **************************************************************************************************
     696        4030 :    SUBROUTINE make_full_single_inverse(preconditioner_env, matrix_c0, matrix_h, energy_gap, matrix_s)
     697             :       TYPE(preconditioner_type)                          :: preconditioner_env
     698             :       TYPE(cp_fm_type), INTENT(IN)                       :: matrix_c0
     699             :       TYPE(dbcsr_type), POINTER                          :: matrix_h
     700             :       REAL(KIND=dp)                                      :: energy_gap
     701             :       TYPE(dbcsr_type), OPTIONAL, POINTER                :: matrix_s
     702             : 
     703             :       CHARACTER(len=*), PARAMETER :: routineN = 'make_full_single_inverse'
     704             : 
     705             :       INTEGER                                            :: handle, k, n
     706             :       REAL(KIND=dp)                                      :: max_ev, min_ev, pre_shift
     707             :       TYPE(arnoldi_env_type)                             :: arnoldi_env
     708        4030 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrices
     709             :       TYPE(dbcsr_type), TARGET                           :: dbcsr_cThc, dbcsr_hc, dbcsr_sc, mo_dbcsr
     710             : 
     711        4030 :       CALL timeset(routineN, handle)
     712             : 
     713             :       ! Allocate all working matrices needed
     714        4030 :       CALL cp_fm_get_info(matrix_c0, nrow_global=n, ncol_global=k)
     715             :       ! copy the fm MO's to a sparse matrix, can be solved better if the sparse version is already present
     716             :       ! but for the time beeing this will do
     717        4030 :       CALL cp_fm_to_dbcsr_row_template(mo_dbcsr, matrix_c0, matrix_h)
     718        4030 :       CALL dbcsr_create(dbcsr_sc, template=mo_dbcsr)
     719        4030 :       CALL dbcsr_create(dbcsr_hc, template=mo_dbcsr)
     720        4030 :       CALL cp_dbcsr_m_by_n_from_template(dbcsr_cThc, matrix_h, k, k, sym=dbcsr_type_symmetric)
     721             : 
     722             :       ! Check whether the output matrix was already created, if not do it now
     723        4030 :       IF (.NOT. ASSOCIATED(preconditioner_env%sparse_matrix)) THEN
     724        4030 :          ALLOCATE (preconditioner_env%sparse_matrix)
     725             :       END IF
     726             : 
     727             :       ! Put the first term of the preconditioner (H) into the output matrix
     728        4030 :       CALL dbcsr_copy(preconditioner_env%sparse_matrix, matrix_h)
     729             : 
     730             :       ! Precompute some matrices
     731             :       ! S*C, if orthonormal this will be simply C so a copy will do
     732        4030 :       IF (PRESENT(matrix_s)) THEN
     733        3638 :          CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_s, mo_dbcsr, 0.0_dp, dbcsr_sc)
     734             :       ELSE
     735         392 :          CALL dbcsr_copy(dbcsr_sc, mo_dbcsr)
     736             :       END IF
     737             : 
     738             : !----------------------------compute the occupied subspace and shift it ------------------------------------
     739             :       ! cT*H*C which will be used to shift the occupied states to 0
     740        4030 :       CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_h, mo_dbcsr, 0.0_dp, dbcsr_hc)
     741        4030 :       CALL dbcsr_multiply("T", "N", 1.0_dp, mo_dbcsr, dbcsr_hc, 0.0_dp, dbcsr_cThc)
     742             : 
     743             :       ! Compute the Energy of the HOMO. We will use this as a reference energy
     744        8060 :       ALLOCATE (matrices(1))
     745        4030 :       matrices(1)%matrix => dbcsr_cThc
     746             :       CALL setup_arnoldi_env(arnoldi_env, matrices, max_iter=20, threshold=1.0E-3_dp, selection_crit=2, &
     747        4030 :                              nval_request=1, nrestarts=8, generalized_ev=.FALSE., iram=.FALSE.)
     748        4030 :       IF (ASSOCIATED(preconditioner_env%max_ev_vector)) &
     749        2315 :          CALL set_arnoldi_initial_vector(arnoldi_env, preconditioner_env%max_ev_vector)
     750        4030 :       CALL arnoldi_ev(matrices, arnoldi_env)
     751        4030 :       max_ev = REAL(get_selected_ritz_val(arnoldi_env, 1), dp)
     752             : 
     753             :       ! save the ev as guess for the next time
     754        4030 :       IF (.NOT. ASSOCIATED(preconditioner_env%max_ev_vector)) ALLOCATE (preconditioner_env%max_ev_vector)
     755        4030 :       CALL get_selected_ritz_vector(arnoldi_env, 1, matrices(1)%matrix, preconditioner_env%max_ev_vector)
     756        4030 :       CALL deallocate_arnoldi_env(arnoldi_env)
     757        4030 :       DEALLOCATE (matrices)
     758             : 
     759             :       ! Lets shift the occupied states a bit further up, -1.0 because we gonna subtract it from H
     760        4030 :       CALL dbcsr_add_on_diag(dbcsr_cThc, -0.5_dp)
     761             :       ! Get the AO representation of the shift (see above why S is needed), W-matrix like object
     762        4030 :       CALL dbcsr_multiply("N", "N", 2.0_dp, dbcsr_sc, dbcsr_cThc, 0.0_dp, dbcsr_hc)
     763        4030 :       CALL dbcsr_multiply("N", "T", -1.0_dp, dbcsr_hc, dbcsr_sc, 1.0_dp, preconditioner_env%sparse_matrix)
     764             : 
     765             : !-------------------------------------compute eigenvalues of H ----------------------------------------------
     766             :       ! Setup the arnoldi procedure to compute the lowest ev. if S is present this has to be the generalized ev
     767        4030 :       IF (PRESENT(matrix_s)) THEN
     768       10914 :          ALLOCATE (matrices(2))
     769        3638 :          matrices(1)%matrix => preconditioner_env%sparse_matrix
     770        3638 :          matrices(2)%matrix => matrix_s
     771             :          CALL setup_arnoldi_env(arnoldi_env, matrices, max_iter=20, threshold=2.0E-2_dp, selection_crit=3, &
     772        3638 :                                 nval_request=1, nrestarts=21, generalized_ev=.TRUE., iram=.FALSE.)
     773             :       ELSE
     774         784 :          ALLOCATE (matrices(1))
     775         392 :          matrices(1)%matrix => preconditioner_env%sparse_matrix
     776             :          CALL setup_arnoldi_env(arnoldi_env, matrices, max_iter=20, threshold=2.0E-2_dp, selection_crit=3, &
     777         392 :                                 nval_request=1, nrestarts=8, generalized_ev=.FALSE., iram=.FALSE.)
     778             :       END IF
     779        4030 :       IF (ASSOCIATED(preconditioner_env%min_ev_vector)) &
     780        2315 :          CALL set_arnoldi_initial_vector(arnoldi_env, preconditioner_env%min_ev_vector)
     781             : 
     782             :       ! compute the LUMO energy
     783        4030 :       CALL arnoldi_ev(matrices, arnoldi_env)
     784        4030 :       min_eV = REAL(get_selected_ritz_val(arnoldi_env, 1), dp)
     785             : 
     786             :       ! save the lumo vector for restarting in the next step
     787        4030 :       IF (.NOT. ASSOCIATED(preconditioner_env%min_ev_vector)) ALLOCATE (preconditioner_env%min_ev_vector)
     788        4030 :       CALL get_selected_ritz_vector(arnoldi_env, 1, matrices(1)%matrix, preconditioner_env%min_ev_vector)
     789        4030 :       CALL deallocate_arnoldi_env(arnoldi_env)
     790        4030 :       DEALLOCATE (matrices)
     791             : 
     792             : !-------------------------------------compute eigenvalues of H ----------------------------------------------
     793             :       ! Shift the Lumo to the 1.5*the computed energy_gap or the external energy gap value
     794             :       ! The factor 1.5 is determined by trying. If the LUMO is positive, enough, just leave it alone
     795        4030 :       pre_shift = MAX(1.5_dp*(min_ev - max_ev), energy_gap)
     796        4030 :       IF (min_ev .LT. pre_shift) THEN
     797        4022 :          pre_shift = pre_shift - min_ev
     798             :       ELSE
     799           8 :          pre_shift = 0.0_dp
     800             :       END IF
     801        4030 :       IF (PRESENT(matrix_s)) THEN
     802        3638 :          CALL dbcsr_add(preconditioner_env%sparse_matrix, matrix_s, 1.0_dp, pre_shift)
     803             :       ELSE
     804         392 :          CALL dbcsr_add_on_diag(preconditioner_env%sparse_matrix, pre_shift)
     805             :       END IF
     806             : 
     807        4030 :       CALL dbcsr_release(mo_dbcsr)
     808        4030 :       CALL dbcsr_release(dbcsr_hc)
     809        4030 :       CALL dbcsr_release(dbcsr_sc)
     810        4030 :       CALL dbcsr_release(dbcsr_cThc)
     811             : 
     812        4030 :       CALL timestop(handle)
     813             : 
     814        4030 :    END SUBROUTINE make_full_single_inverse
     815             : 
     816             : END MODULE preconditioner_makes
     817             : 

Generated by: LCOV version 1.15