LCOV - code coverage report
Current view: top level - src - almo_scf_methods.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:4c33f95) Lines: 807 1058 76.3 %
Date: 2025-01-30 06:53:08 Functions: 20 25 80.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 Subroutines for ALMO SCF
      10             : !> \par History
      11             : !>       2011.06 created [Rustam Z Khaliullin]
      12             : !>       2018.09 smearing support [Ruben Staub]
      13             : !> \author Rustam Z Khaliullin
      14             : ! **************************************************************************************************
      15             : MODULE almo_scf_methods
      16             :    USE almo_scf_types,                  ONLY: almo_scf_env_type,&
      17             :                                               almo_scf_history_type
      18             :    USE bibliography,                    ONLY: Kolafa2004,&
      19             :                                               Kuhne2007,&
      20             :                                               cite_reference
      21             :    USE cp_blacs_env,                    ONLY: cp_blacs_env_type
      22             :    USE cp_dbcsr_api,                    ONLY: &
      23             :         dbcsr_add, dbcsr_add_on_diag, dbcsr_copy, dbcsr_create, dbcsr_distribution_get, &
      24             :         dbcsr_distribution_type, dbcsr_filter, dbcsr_finalize, dbcsr_frobenius_norm, &
      25             :         dbcsr_get_block_p, dbcsr_get_diag, dbcsr_get_info, dbcsr_get_stored_coordinates, &
      26             :         dbcsr_init_random, dbcsr_iterator_blocks_left, dbcsr_iterator_next_block, &
      27             :         dbcsr_iterator_start, dbcsr_iterator_stop, dbcsr_iterator_type, dbcsr_multiply, &
      28             :         dbcsr_nblkcols_total, dbcsr_nblkrows_total, dbcsr_print, dbcsr_release, &
      29             :         dbcsr_reserve_block2d, dbcsr_scale_by_vector, dbcsr_set, dbcsr_set_diag, dbcsr_transposed, &
      30             :         dbcsr_type, dbcsr_type_no_symmetry, dbcsr_type_symmetric, dbcsr_work_create
      31             :    USE cp_dbcsr_cholesky,               ONLY: cp_dbcsr_cholesky_decompose,&
      32             :                                               cp_dbcsr_cholesky_invert
      33             :    USE cp_log_handling,                 ONLY: cp_get_default_logger,&
      34             :                                               cp_logger_get_default_unit_nr,&
      35             :                                               cp_logger_type
      36             :    USE domain_submatrix_methods,        ONLY: &
      37             :         add_submatrices, construct_dbcsr_from_submatrices, construct_submatrices, &
      38             :         copy_submatrices, copy_submatrix_data, init_submatrices, multiply_submatrices, &
      39             :         print_submatrices, release_submatrices
      40             :    USE domain_submatrix_types,          ONLY: domain_map_type,&
      41             :                                               domain_submatrix_type,&
      42             :                                               select_row,&
      43             :                                               select_row_col
      44             :    USE fermi_utils,                     ONLY: FermiFixed
      45             : !! for smearing
      46             :    USE input_constants,                 ONLY: almo_domain_layout_molecular,&
      47             :                                               almo_mat_distr_atomic,&
      48             :                                               almo_scf_diag,&
      49             :                                               spd_inversion_dense_cholesky,&
      50             :                                               spd_inversion_ls_hotelling,&
      51             :                                               spd_inversion_ls_taylor
      52             :    USE iterate_matrix,                  ONLY: invert_Hotelling,&
      53             :                                               invert_Taylor,&
      54             :                                               matrix_sqrt_Newton_Schulz
      55             :    USE kinds,                           ONLY: dp
      56             :    USE mathlib,                         ONLY: binomial,&
      57             :                                               invmat_symm
      58             :    USE message_passing,                 ONLY: mp_comm_type,&
      59             :                                               mp_para_env_type
      60             :    USE util,                            ONLY: sort
      61             : #include "./base/base_uses.f90"
      62             : 
      63             :    IMPLICIT NONE
      64             : 
      65             :    PRIVATE
      66             : 
      67             :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'almo_scf_methods'
      68             : 
      69             :    PUBLIC almo_scf_ks_to_ks_blk, almo_scf_p_blk_to_t_blk, &
      70             :       almo_scf_t_to_proj, almo_scf_ks_blk_to_tv_blk, &
      71             :       almo_scf_ks_xx_to_tv_xx, almo_scf_t_rescaling, &
      72             :       apply_projector, get_overlap, &
      73             :       generator_to_unitary, &
      74             :       orthogonalize_mos, &
      75             :       pseudo_invert_diagonal_blk, construct_test, &
      76             :       construct_domain_preconditioner, &
      77             :       apply_domain_operators, &
      78             :       construct_domain_s_inv, &
      79             :       construct_domain_s_sqrt, &
      80             :       distribute_domains, &
      81             :       almo_scf_ks_to_ks_xx, &
      82             :       construct_domain_r_down, &
      83             :       xalmo_initial_guess, &
      84             :       fill_matrix_with_ones
      85             : 
      86             : CONTAINS
      87             : 
      88             : ! **************************************************************************************************
      89             : !> \brief Fill all matrix blocks with 1.0_dp
      90             : !> \param matrix ...
      91             : !> \par History
      92             : !>       2019.09 created [Rustam Z Khaliullin]
      93             : !> \author Rustam Z Khaliullin
      94             : ! **************************************************************************************************
      95           0 :    SUBROUTINE fill_matrix_with_ones(matrix)
      96             : 
      97             :       TYPE(dbcsr_type), INTENT(INOUT)                    :: matrix
      98             : 
      99             :       INTEGER                                            :: col, hold, iblock_col, iblock_row, &
     100             :                                                             mynode, nblkcols_tot, nblkrows_tot, row
     101             :       LOGICAL                                            :: tr
     102           0 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: p_new_block
     103             :       TYPE(dbcsr_distribution_type)                      :: dist
     104             : 
     105           0 :       CALL dbcsr_get_info(matrix, distribution=dist)
     106           0 :       CALL dbcsr_distribution_get(dist, mynode=mynode)
     107           0 :       CALL dbcsr_work_create(matrix, work_mutable=.TRUE.)
     108           0 :       nblkrows_tot = dbcsr_nblkrows_total(matrix)
     109           0 :       nblkcols_tot = dbcsr_nblkcols_total(matrix)
     110           0 :       DO row = 1, nblkrows_tot
     111           0 :          DO col = 1, nblkcols_tot
     112           0 :             tr = .FALSE.
     113           0 :             iblock_row = row
     114           0 :             iblock_col = col
     115             :             CALL dbcsr_get_stored_coordinates(matrix, &
     116           0 :                                               iblock_row, iblock_col, hold)
     117           0 :             IF (hold .EQ. mynode) THEN
     118           0 :                NULLIFY (p_new_block)
     119             :                CALL dbcsr_reserve_block2d(matrix, &
     120           0 :                                           iblock_row, iblock_col, p_new_block)
     121           0 :                CPASSERT(ASSOCIATED(p_new_block))
     122           0 :                p_new_block(:, :) = 1.0_dp
     123             :             END IF
     124             :          END DO
     125             :       END DO
     126           0 :       CALL dbcsr_finalize(matrix)
     127             : 
     128           0 :    END SUBROUTINE fill_matrix_with_ones
     129             : 
     130             : ! **************************************************************************************************
     131             : !> \brief builds projected KS matrices for the overlapping domains
     132             : !>        also computes the DIIS error vector as a by-product
     133             : !> \param almo_scf_env ...
     134             : !> \par History
     135             : !>       2013.03 created [Rustam Z Khaliullin]
     136             : !> \author Rustam Z Khaliullin
     137             : ! **************************************************************************************************
     138           2 :    SUBROUTINE almo_scf_ks_to_ks_xx(almo_scf_env)
     139             : 
     140             :       TYPE(almo_scf_env_type), INTENT(INOUT)             :: almo_scf_env
     141             : 
     142             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'almo_scf_ks_to_ks_xx'
     143             : 
     144             :       INTEGER                                            :: handle, ispin, ndomains
     145             :       REAL(KIND=dp)                                      :: eps_multiply
     146             :       TYPE(dbcsr_type) :: matrix_tmp1, matrix_tmp2, matrix_tmp3, matrix_tmp4, matrix_tmp5, &
     147             :          matrix_tmp6, matrix_tmp7, matrix_tmp8, matrix_tmp9
     148             :       TYPE(domain_submatrix_type), ALLOCATABLE, &
     149           2 :          DIMENSION(:)                                    :: subm_tmp1, subm_tmp2, subm_tmp3
     150             : 
     151           2 :       CALL timeset(routineN, handle)
     152             : 
     153           2 :       eps_multiply = almo_scf_env%eps_filter
     154             : 
     155           4 :       DO ispin = 1, almo_scf_env%nspins
     156             : 
     157           2 :          ndomains = dbcsr_nblkcols_total(almo_scf_env%quench_t(ispin))
     158             : 
     159             :          ! 0. Create KS_xx
     160             :          CALL construct_submatrices( &
     161             :             almo_scf_env%matrix_ks(ispin), &
     162             :             almo_scf_env%domain_ks_xx(:, ispin), &
     163             :             almo_scf_env%quench_t(ispin), &
     164             :             almo_scf_env%domain_map(ispin), &
     165             :             almo_scf_env%cpu_of_domain, &
     166           2 :             select_row_col)
     167             : 
     168             :          !!!!! RZK-warning MAKE SURE THAT YOU NEED BLOCKS OUTSIDE QUENCH_T
     169             :          !!!!! FOR ALL NO-MATRICES NOT COMPUTING THEM CAN SAVE LOTS OF TIME
     170             : 
     171             :          ! 1. TMP1=KS.T
     172             :          !    Cost: NOn
     173             :          !matrix_tmp1 = create NxO, full
     174             :          CALL dbcsr_create(matrix_tmp1, &
     175           2 :                            template=almo_scf_env%matrix_t(ispin))
     176             :          CALL dbcsr_multiply("N", "N", 1.0_dp, almo_scf_env%matrix_ks(ispin), &
     177             :                              almo_scf_env%matrix_t(ispin), &
     178             :                              0.0_dp, matrix_tmp1, &
     179           2 :                              filter_eps=eps_multiply)
     180             : 
     181             :          ! 2. TMP2=TMP1.SigInv=KS.T.SigInv
     182             :          !    Cost: NOO
     183             :          !matrix_tmp2 = create NxO, full
     184             :          CALL dbcsr_create(matrix_tmp2, &
     185           2 :                            template=almo_scf_env%matrix_t(ispin))
     186             :          CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_tmp1, &
     187             :                              almo_scf_env%matrix_sigma_inv(ispin), &
     188             :                              0.0_dp, matrix_tmp2, &
     189           2 :                              filter_eps=eps_multiply)
     190             : 
     191             :          ! 3. TMP1=S.T
     192             :          !    Cost: NOn
     193             :          CALL dbcsr_multiply("N", "N", 1.0_dp, almo_scf_env%matrix_s(1), &
     194             :                              almo_scf_env%matrix_t(ispin), &
     195             :                              0.0_dp, matrix_tmp1, &
     196           2 :                              filter_eps=eps_multiply)
     197             : 
     198             :          ! 4. TMP4=TMP2.tr(TMP1)=KS.T.SigInv.tr(T).S
     199             :          !    Cost: NNO
     200             :          !matrix_tmp4 = create NxN
     201             :          CALL dbcsr_create(matrix_tmp4, &
     202             :                            template=almo_scf_env%matrix_s(1), &
     203           2 :                            matrix_type=dbcsr_type_no_symmetry)
     204             :          CALL dbcsr_multiply("N", "T", 1.0_dp, matrix_tmp2, &
     205             :                              matrix_tmp1, &
     206             :                              0.0_dp, matrix_tmp4, &
     207           2 :                              filter_eps=eps_multiply)
     208             : 
     209             :          ! 5. KS_xx=KS_xx-TMP4_xx-tr(TMP4_xx)
     210          16 :          ALLOCATE (subm_tmp1(ndomains))
     211           2 :          CALL init_submatrices(subm_tmp1)
     212             :          CALL construct_submatrices( &
     213             :             matrix_tmp4, &
     214             :             subm_tmp1, &
     215             :             almo_scf_env%quench_t(ispin), &
     216             :             almo_scf_env%domain_map(ispin), &
     217             :             almo_scf_env%cpu_of_domain, &
     218           2 :             select_row_col)
     219             :          CALL add_submatrices(1.0_dp, almo_scf_env%domain_ks_xx(:, ispin), &
     220           2 :                               -1.0_dp, subm_tmp1, 'N')
     221             :          CALL add_submatrices(1.0_dp, almo_scf_env%domain_ks_xx(:, ispin), &
     222           2 :                               -1.0_dp, subm_tmp1, 'T')
     223             : 
     224             :          ! 6. TMP3=tr(TMP4).T=S.T.SigInv.tr(T).KS.T
     225             :          !    Cost: NOn
     226             :          !matrix_tmp3 = create NxO, full
     227             :          CALL dbcsr_create(matrix_tmp3, &
     228             :                            template=almo_scf_env%matrix_t(ispin), &
     229           2 :                            matrix_type=dbcsr_type_no_symmetry)
     230             :          CALL dbcsr_multiply("T", "N", 1.0_dp, &
     231             :                              matrix_tmp4, &
     232             :                              almo_scf_env%matrix_t(ispin), &
     233             :                              0.0_dp, matrix_tmp3, &
     234           2 :                              filter_eps=eps_multiply)
     235           2 :          CALL dbcsr_release(matrix_tmp4)
     236             : 
     237             :          ! 8. TMP6=TMP3.SigInv=S.T.SigInv.tr(T).KS.T.SigInv
     238             :          !    Cost: NOO
     239             :          !matrix_tmp6 = create NxO, full
     240             :          CALL dbcsr_create(matrix_tmp6, &
     241             :                            template=almo_scf_env%matrix_t(ispin), &
     242           2 :                            matrix_type=dbcsr_type_no_symmetry)
     243             :          CALL dbcsr_multiply("N", "N", 1.0_dp, &
     244             :                              matrix_tmp3, &
     245             :                              almo_scf_env%matrix_sigma_inv(ispin), &
     246             :                              0.0_dp, matrix_tmp6, &
     247           2 :                              filter_eps=eps_multiply)
     248             : 
     249             :          ! 8A. Use intermediate matrices to evaluate the gradient/error
     250             :          !     Err=(TMP2-TMP6)_q=(KS.T.SigInv-S.T.SigInv.tr(T).KS.T.SigInv)_q
     251             :          ! error vector in AO-MO basis
     252             :          CALL dbcsr_copy(almo_scf_env%matrix_err_xx(ispin), &
     253           2 :                          almo_scf_env%quench_t(ispin))
     254             :          CALL dbcsr_copy(almo_scf_env%matrix_err_xx(ispin), &
     255           2 :                          matrix_tmp2, keep_sparsity=.TRUE.)
     256             :          CALL dbcsr_create(matrix_tmp4, &
     257             :                            template=almo_scf_env%matrix_t(ispin), &
     258           2 :                            matrix_type=dbcsr_type_no_symmetry)
     259             :          CALL dbcsr_copy(matrix_tmp4, &
     260           2 :                          almo_scf_env%quench_t(ispin))
     261             :          CALL dbcsr_copy(matrix_tmp4, &
     262           2 :                          matrix_tmp6, keep_sparsity=.TRUE.)
     263             :          CALL dbcsr_add(almo_scf_env%matrix_err_xx(ispin), &
     264           2 :                         matrix_tmp4, 1.0_dp, -1.0_dp)
     265           2 :          CALL dbcsr_release(matrix_tmp4)
     266             :          !
     267             :          ! error vector in AO-AO basis
     268             :          ! RZK-warning tmp4 can be created using the sparsity pattern,
     269             :          ! then retain_sparsity can be used to perform the multiply
     270             :          ! this will save some time
     271             :          CALL dbcsr_copy(matrix_tmp3, &
     272           2 :                          matrix_tmp2)
     273             :          CALL dbcsr_add(matrix_tmp3, &
     274           2 :                         matrix_tmp6, 1.0_dp, -1.0_dp)
     275             :          CALL dbcsr_create(matrix_tmp4, &
     276             :                            template=almo_scf_env%matrix_s(1), &
     277           2 :                            matrix_type=dbcsr_type_no_symmetry)
     278             :          CALL dbcsr_multiply("N", "T", 1.0_dp, &
     279             :                              matrix_tmp3, &
     280             :                              almo_scf_env%matrix_t(ispin), &
     281             :                              0.0_dp, matrix_tmp4, &
     282           2 :                              filter_eps=eps_multiply)
     283             :          CALL construct_submatrices( &
     284             :             matrix_tmp4, &
     285             :             almo_scf_env%domain_err(:, ispin), &
     286             :             almo_scf_env%quench_t(ispin), &
     287             :             almo_scf_env%domain_map(ispin), &
     288             :             almo_scf_env%cpu_of_domain, &
     289           2 :             select_row_col)
     290           2 :          CALL dbcsr_release(matrix_tmp4)
     291             :          ! domain_err submatrices are in down-up representation
     292             :          ! bring them into the orthogonalized basis
     293          14 :          ALLOCATE (subm_tmp2(ndomains))
     294           2 :          CALL init_submatrices(subm_tmp2)
     295             :          CALL multiply_submatrices('N', 'N', 1.0_dp, &
     296             :                                    almo_scf_env%domain_err(:, ispin), &
     297           2 :                                    almo_scf_env%domain_s_sqrt(:, ispin), 0.0_dp, subm_tmp2)
     298             :          CALL multiply_submatrices('N', 'N', 1.0_dp, &
     299             :                                    almo_scf_env%domain_s_sqrt_inv(:, ispin), &
     300           2 :                                    subm_tmp2, 0.0_dp, almo_scf_env%domain_err(:, ispin))
     301             : 
     302             :          ! 9. TMP5=TMP6.tr(TMP1)=S.T.SigInv.tr(T).KS.T.SigInv.tr(T).S
     303             :          !    Cost: NNO
     304             :          !    matrix_tmp5 = create NxN, full
     305             :          ! RZK-warning tmp5 can be created using the sparsity pattern,
     306             :          ! then retain_sparsity can be used to perform the multiply
     307             :          ! this will save some time
     308             :          CALL dbcsr_create(matrix_tmp5, &
     309             :                            template=almo_scf_env%matrix_s(1), &
     310           2 :                            matrix_type=dbcsr_type_no_symmetry)
     311             :          CALL dbcsr_multiply("N", "T", 1.0_dp, &
     312             :                              matrix_tmp6, &
     313             :                              matrix_tmp1, &
     314             :                              0.0_dp, matrix_tmp5, &
     315           2 :                              filter_eps=eps_multiply)
     316             : 
     317             :          ! 10. KS_xx=KS_xx+TMP5_xx
     318             :          CALL construct_submatrices( &
     319             :             matrix_tmp5, &
     320             :             subm_tmp1, &
     321             :             almo_scf_env%quench_t(ispin), &
     322             :             almo_scf_env%domain_map(ispin), &
     323             :             almo_scf_env%cpu_of_domain, &
     324           2 :             select_row_col)
     325           2 :          CALL dbcsr_release(matrix_tmp5)
     326             :          CALL add_submatrices(1.0_dp, almo_scf_env%domain_ks_xx(:, ispin), &
     327           2 :                               1.0_dp, subm_tmp1, 'N')
     328             : 
     329             :          ! 11. KS_xx=KS_xx + [S.T]_xx.[SigInv.tr(T).KS.(1-T.SigInv.tr(T).S)]_xx + transposed
     330          14 :          ALLOCATE (subm_tmp3(ndomains))
     331           2 :          CALL init_submatrices(subm_tmp3)
     332             :          CALL construct_submatrices( &
     333             :             matrix_tmp2, &
     334             :             subm_tmp2, &
     335             :             almo_scf_env%quench_t(ispin), &
     336             :             almo_scf_env%domain_map(ispin), &
     337             :             almo_scf_env%cpu_of_domain, &
     338           2 :             select_row)
     339             :          CALL construct_submatrices( &
     340             :             matrix_tmp6, &
     341             :             subm_tmp3, &
     342             :             almo_scf_env%quench_t(ispin), &
     343             :             almo_scf_env%domain_map(ispin), &
     344             :             almo_scf_env%cpu_of_domain, &
     345           2 :             select_row)
     346           2 :          CALL dbcsr_release(matrix_tmp6)
     347             :          CALL add_submatrices(1.0_dp, subm_tmp2, &
     348           2 :                               -1.0_dp, subm_tmp3, 'N')
     349             :          CALL construct_submatrices( &
     350             :             matrix_tmp1, &
     351             :             subm_tmp3, &
     352             :             almo_scf_env%quench_t(ispin), &
     353             :             almo_scf_env%domain_map(ispin), &
     354             :             almo_scf_env%cpu_of_domain, &
     355           2 :             select_row)
     356             :          CALL multiply_submatrices('N', 'T', 1.0_dp, subm_tmp2, &
     357           2 :                                    subm_tmp3, 0.0_dp, subm_tmp1)
     358             :          CALL add_submatrices(1.0_dp, almo_scf_env%domain_ks_xx(:, ispin), &
     359           2 :                               1.0_dp, subm_tmp1, 'N')
     360             :          CALL add_submatrices(1.0_dp, almo_scf_env%domain_ks_xx(:, ispin), &
     361           2 :                               1.0_dp, subm_tmp1, 'T')
     362             : 
     363             :          ! 12. TMP7=tr(T).KS.T.SigInv
     364             :          CALL dbcsr_create(matrix_tmp7, &
     365             :                            template=almo_scf_env%matrix_sigma_blk(ispin), &
     366           2 :                            matrix_type=dbcsr_type_no_symmetry)
     367             :          CALL dbcsr_multiply("T", "N", 1.0_dp, &
     368             :                              almo_scf_env%matrix_t(ispin), &
     369             :                              matrix_tmp2, &
     370             :                              0.0_dp, matrix_tmp7, &
     371           2 :                              filter_eps=eps_multiply)
     372             : 
     373             :          ! 13. TMP8=[SigInv.tr(T).KS.T.SigInv]_xx
     374             :          CALL dbcsr_create(matrix_tmp8, &
     375             :                            template=almo_scf_env%matrix_sigma_blk(ispin), &
     376           2 :                            matrix_type=dbcsr_type_symmetric)
     377           2 :          CALL dbcsr_copy(matrix_tmp8, almo_scf_env%matrix_sigma_blk(ispin))
     378             :          CALL dbcsr_multiply("N", "N", 1.0_dp, &
     379             :                              almo_scf_env%matrix_sigma_inv(ispin), &
     380             :                              matrix_tmp7, &
     381             :                              0.0_dp, matrix_tmp8, &
     382             :                              retain_sparsity=.TRUE., &
     383           2 :                              filter_eps=eps_multiply)
     384           2 :          CALL dbcsr_release(matrix_tmp7)
     385             : 
     386             :          ! 13. TMP9=[S.T]_xx
     387             :          CALL dbcsr_create(matrix_tmp9, &
     388             :                            template=almo_scf_env%matrix_t(ispin), &
     389           2 :                            matrix_type=dbcsr_type_no_symmetry)
     390           2 :          CALL dbcsr_copy(matrix_tmp9, almo_scf_env%quench_t(ispin))
     391           2 :          CALL dbcsr_copy(matrix_tmp9, matrix_tmp1, keep_sparsity=.TRUE.)
     392             : 
     393             :          ! 14. TMP3=TMP9.TMP8=[S.T]_xx.[SigInv.tr(T).KS.T.SigInv]_xx
     394             :          CALL dbcsr_multiply("N", "N", 1.0_dp, &
     395             :                              matrix_tmp9, &
     396             :                              matrix_tmp8, &
     397             :                              0.0_dp, matrix_tmp3, &
     398           2 :                              filter_eps=eps_multiply)
     399           2 :          CALL dbcsr_release(matrix_tmp8)
     400           2 :          CALL dbcsr_release(matrix_tmp9)
     401             : 
     402             :          ! 15. KS_xx=KS_xx+[S.T]_xx.[SigInv.tr(T).KS.T.SigInv]_xx.[tr(T).S]_xx
     403             :          CALL construct_submatrices( &
     404             :             matrix_tmp3, &
     405             :             subm_tmp2, &
     406             :             almo_scf_env%quench_t(ispin), &
     407             :             almo_scf_env%domain_map(ispin), &
     408             :             almo_scf_env%cpu_of_domain, &
     409           2 :             select_row)
     410             :          CALL multiply_submatrices('N', 'T', 1.0_dp, subm_tmp2, &
     411           2 :                                    subm_tmp3, 0.0_dp, subm_tmp1)
     412             :          CALL add_submatrices(1.0_dp, almo_scf_env%domain_ks_xx(:, ispin), &
     413           2 :                               1.0_dp, subm_tmp1, 'N')
     414             : 
     415             :          !!!!!!! use intermediate matrices to get the error vector !!!!!!!
     416             :          !!!!!!! make sure s_blk_sqrt and its inverse exist (i.e. we use diag algorithm)
     417             :          !CPPrecondition(almo_scf_env%almo_update_algorithm.eq.almo_scf_diag,cp_failure_level,routineP,failure)
     418             :          !! tmp_err = (1-S.T_blk.SigInv.tr(T_blk)).F.T_blk.SigInv
     419             :          !CALL dbcsr_init(matrix_tmp_err)
     420             :          !CALL dbcsr_create(matrix_tmp_err,&
     421             :          !        template=almo_scf_env%matrix_t(ispin))
     422             :          !CALL dbcsr_copy(matrix_tmp_err,&
     423             :          !        matrix_tmp2)
     424             :          !CALL dbcsr_add(matrix_tmp_err,matrix_tmp3,&
     425             :          !        1.0_dp,-1.0_dp)
     426             :          !! err_blk = tmp_err.tr(T_blk)
     427             :          !CALL dbcsr_copy(almo_scf_env%matrix_err_blk(ispin),&
     428             :          !        almo_scf_env%matrix_s_blk_sqrt(1))
     429             :          !CALL dbcsr_multiply("N", "T", 1.0_dp, matrix_tmp_err,&
     430             :          !        almo_scf_env%matrix_t(ispin),&
     431             :          !        0.0_dp, almo_scf_env%matrix_err_blk(ispin),&
     432             :          !        retain_sparsity=.TRUE.,&
     433             :          !        filter_eps=eps_multiply)
     434             :          !CALL dbcsr_release(matrix_tmp_err)
     435             :          !! bring to the orthogonal basis
     436             :          !! err_blk = (S_blk^-1/2).err_blk.(S_blk^1/2)
     437             :          !CALL dbcsr_init(matrix_tmp_err)
     438             :          !CALL dbcsr_create(matrix_tmp_err,&
     439             :          !        template=almo_scf_env%matrix_err_blk(ispin))
     440             :          !CALL dbcsr_multiply("N", "N", 1.0_dp,&
     441             :          !        almo_scf_env%matrix_err_blk(ispin),&
     442             :          !        almo_scf_env%matrix_s_blk_sqrt(1),&
     443             :          !        0.0_dp, matrix_tmp_err,&
     444             :          !        filter_eps=eps_multiply)
     445             :          !CALL dbcsr_multiply("N", "N", 1.0_dp,&
     446             :          !        almo_scf_env%matrix_s_blk_sqrt_inv(1),&
     447             :          !        matrix_tmp_err,&
     448             :          !        0.0_dp, almo_scf_env%matrix_err_blk(ispin),&
     449             :          !        filter_eps=eps_multiply)
     450             :          !! subtract transpose
     451             :          !CALL dbcsr_transposed(matrix_tmp_err,&
     452             :          !        almo_scf_env%matrix_err_blk(ispin))
     453             :          !CALL dbcsr_add(almo_scf_env%matrix_err_blk(ispin),&
     454             :          !        matrix_tmp_err,&
     455             :          !        1.0_dp,-1.0_dp)
     456             :          !CALL dbcsr_release(matrix_tmp_err)
     457             :          !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
     458             : 
     459           2 :          CALL release_submatrices(subm_tmp3)
     460           2 :          CALL release_submatrices(subm_tmp2)
     461           2 :          CALL release_submatrices(subm_tmp1)
     462          12 :          DEALLOCATE (subm_tmp3)
     463          12 :          DEALLOCATE (subm_tmp2)
     464          12 :          DEALLOCATE (subm_tmp1)
     465           2 :          CALL dbcsr_release(matrix_tmp3)
     466           2 :          CALL dbcsr_release(matrix_tmp2)
     467           4 :          CALL dbcsr_release(matrix_tmp1)
     468             : 
     469             :       END DO ! spins
     470             : 
     471           2 :       CALL timestop(handle)
     472             : 
     473           4 :    END SUBROUTINE almo_scf_ks_to_ks_xx
     474             : 
     475             : ! **************************************************************************************************
     476             : !> \brief computes the projected KS from the total KS matrix
     477             : !>        also computes the DIIS error vector as a by-product
     478             : !> \param almo_scf_env ...
     479             : !> \par History
     480             : !>       2011.06 created [Rustam Z Khaliullin]
     481             : !> \author Rustam Z Khaliullin
     482             : ! **************************************************************************************************
     483         424 :    SUBROUTINE almo_scf_ks_to_ks_blk(almo_scf_env)
     484             : 
     485             :       TYPE(almo_scf_env_type), INTENT(INOUT)             :: almo_scf_env
     486             : 
     487             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'almo_scf_ks_to_ks_blk'
     488             : 
     489             :       INTEGER                                            :: handle, ispin
     490             :       REAL(KIND=dp)                                      :: eps_multiply
     491             :       TYPE(dbcsr_type) :: matrix_tmp1, matrix_tmp2, matrix_tmp3, matrix_tmp4, matrix_tmp5, &
     492             :          matrix_tmp6, matrix_tmp7, matrix_tmp8, matrix_tmp9, matrix_tmp_err
     493             : 
     494         424 :       CALL timeset(routineN, handle)
     495             : 
     496         424 :       eps_multiply = almo_scf_env%eps_filter
     497             : 
     498         848 :       DO ispin = 1, almo_scf_env%nspins
     499             : 
     500             :          ! 1. TMP1=KS.T_blk
     501             :          !    Cost: NOn
     502             :          !matrix_tmp1 = create NxO, full
     503             :          CALL dbcsr_create(matrix_tmp1, &
     504         424 :                            template=almo_scf_env%matrix_t(ispin))
     505             :          CALL dbcsr_multiply("N", "N", 1.0_dp, almo_scf_env%matrix_ks(ispin), &
     506             :                              almo_scf_env%matrix_t_blk(ispin), &
     507             :                              0.0_dp, matrix_tmp1, &
     508         424 :                              filter_eps=eps_multiply)
     509             :          ! 2. TMP2=TMP1.SigInv=KS.T_blk.SigInv
     510             :          !    Cost: NOO
     511             :          !matrix_tmp2 = create NxO, full
     512             :          CALL dbcsr_create(matrix_tmp2, &
     513         424 :                            template=almo_scf_env%matrix_t(ispin))
     514             :          CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_tmp1, &
     515             :                              almo_scf_env%matrix_sigma_inv(ispin), &
     516             :                              0.0_dp, matrix_tmp2, &
     517         424 :                              filter_eps=eps_multiply)
     518             : 
     519             :          !!!!!! use intermediate matrices to get the error vector !!!!!!!
     520             :          !CALL dbcsr_copy(almo_scf_env%matrix_err_blk(ispin),&
     521             :          !        almo_scf_env%matrix_t_blk(ispin))
     522             :          !CALL dbcsr_copy(almo_scf_env%matrix_err_blk(ispin),&
     523             :          !        matrix_tmp2,&
     524             :          !        keep_sparsity=.TRUE.)
     525             :          !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
     526             : 
     527             :          ! 3. TMP1=S.T_blk
     528             :          !    Cost: NOn
     529             :          CALL dbcsr_multiply("N", "N", 1.0_dp, almo_scf_env%matrix_s(1), &
     530             :                              almo_scf_env%matrix_t_blk(ispin), &
     531             :                              0.0_dp, matrix_tmp1, &
     532         424 :                              filter_eps=eps_multiply)
     533             : 
     534             :          ! 4. TMP4_blk=TMP2.tr(TMP1)=KS.T_blk.SigInv.tr(T_blk).S
     535             :          !    Cost: NnO
     536             :          !matrix_tmp4 = create NxN, blk
     537             :          CALL dbcsr_create(matrix_tmp4, &
     538             :                            template=almo_scf_env%matrix_s_blk(1), &
     539         424 :                            matrix_type=dbcsr_type_no_symmetry)
     540         424 :          CALL dbcsr_copy(matrix_tmp4, almo_scf_env%matrix_s_blk(1))
     541             :          CALL dbcsr_multiply("N", "T", 1.0_dp, matrix_tmp2, &
     542             :                              matrix_tmp1, &
     543             :                              0.0_dp, matrix_tmp4, &
     544             :                              retain_sparsity=.TRUE., &
     545         424 :                              filter_eps=eps_multiply)
     546             : 
     547             :          ! 5. KS_blk=KS_blk-TMP4_blk
     548             :          CALL dbcsr_copy(almo_scf_env%matrix_ks_blk(ispin), &
     549         424 :                          almo_scf_env%matrix_ks(ispin), keep_sparsity=.TRUE.)
     550             :          CALL dbcsr_add(almo_scf_env%matrix_ks_blk(ispin), &
     551             :                         matrix_tmp4, &
     552         424 :                         1.0_dp, -1.0_dp)
     553             : 
     554             :          ! 6. TMP5_blk=tr(TMP4_blk)
     555             :          !    KS_blk=KS_blk-tr(TMP4_blk)
     556             :          !matrix_tmp5 = create NxN, blk
     557             :          CALL dbcsr_create(matrix_tmp5, &
     558             :                            template=almo_scf_env%matrix_s_blk(1), &
     559         424 :                            matrix_type=dbcsr_type_no_symmetry)
     560         424 :          CALL dbcsr_transposed(matrix_tmp5, matrix_tmp4)
     561             :          CALL dbcsr_add(almo_scf_env%matrix_ks_blk(ispin), matrix_tmp5, &
     562         424 :                         1.0_dp, -1.0_dp)
     563             : 
     564             :          ! 7. TMP3=tr(T_blk).TMP2=tr(T_blk).KS.T_blk.SigInv
     565             :          !    Cost: OOn
     566             :          !matrix_tmp3 = create OxO, full
     567             :          CALL dbcsr_create(matrix_tmp3, &
     568             :                            template=almo_scf_env%matrix_sigma_inv(ispin), &
     569         424 :                            matrix_type=dbcsr_type_no_symmetry)
     570             :          CALL dbcsr_multiply("T", "N", 1.0_dp, &
     571             :                              almo_scf_env%matrix_t_blk(ispin), &
     572             :                              matrix_tmp2, &
     573             :                              0.0_dp, matrix_tmp3, &
     574         424 :                              filter_eps=eps_multiply)
     575             : 
     576             :          ! 8. TMP6=SigInv.TMP3=SigInv.tr(T_blk).KS.T_blk.SigInv
     577             :          !    Cost: OOO
     578             :          !matrix_tmp6 = create OxO, full
     579             :          CALL dbcsr_create(matrix_tmp6, &
     580             :                            template=almo_scf_env%matrix_sigma_inv(ispin), &
     581         424 :                            matrix_type=dbcsr_type_no_symmetry)
     582             :          CALL dbcsr_multiply("N", "N", 1.0_dp, &
     583             :                              almo_scf_env%matrix_sigma_inv(ispin), &
     584             :                              matrix_tmp3, &
     585             :                              0.0_dp, matrix_tmp6, &
     586         424 :                              filter_eps=eps_multiply)
     587             : 
     588             :          ! 9. TMP3=TMP1.TMP6=S.T_blk.SigInv.tr(T_blk).KS.T_blk.SigInv
     589             :          !    Cost: NOO
     590             :          !matrix_tmp3 = re-create NxO, full
     591         424 :          CALL dbcsr_release(matrix_tmp3)
     592             :          CALL dbcsr_create(matrix_tmp3, &
     593         424 :                            template=almo_scf_env%matrix_t(ispin))
     594             :          CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_tmp1, &
     595             :                              matrix_tmp6, &
     596             :                              0.0_dp, matrix_tmp3, &
     597         424 :                              filter_eps=eps_multiply)
     598             : 
     599             :          !!!!!! use intermediate matrices to get the error vector !!!!!!!
     600             :          !CALL dbcsr_init(matrix_tmp_err)
     601             :          !CALL dbcsr_create(matrix_tmp_err,&
     602             :          !        template=almo_scf_env%matrix_t_blk(ispin))
     603             :          !CALL dbcsr_copy(matrix_tmp_err,&
     604             :          !        almo_scf_env%matrix_t_blk(ispin))
     605             :          !CALL dbcsr_copy(matrix_tmp_err,matrix_tmp3,&
     606             :          !        keep_sparsity=.TRUE.)
     607             :          !CALL dbcsr_add(almo_scf_env%matrix_err_blk(ispin),matrix_tmp_err,&
     608             :          !        1.0_dp,-1.0_dp)
     609             :          !CALL dbcsr_release(matrix_tmp_err)
     610             :          !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
     611             : 
     612             :          !!!!!! use intermediate matrices to get the error vector !!!!!!!
     613             :          !!!!!! make sure s_blk_sqrt and its inverse exist (i.e. we use diag algorithm)
     614         424 :          CPASSERT(almo_scf_env%almo_update_algorithm .EQ. almo_scf_diag)
     615             :          ! tmp_err = (1-S.T_blk.SigInv.tr(T_blk)).F.T_blk.SigInv
     616             :          CALL dbcsr_create(matrix_tmp_err, &
     617         424 :                            template=almo_scf_env%matrix_t_blk(ispin))
     618             :          CALL dbcsr_copy(matrix_tmp_err, &
     619         424 :                          matrix_tmp2)
     620             :          CALL dbcsr_add(matrix_tmp_err, matrix_tmp3, &
     621         424 :                         1.0_dp, -1.0_dp)
     622             :          ! err_blk = tmp_err.tr(T_blk)
     623             :          CALL dbcsr_copy(almo_scf_env%matrix_err_blk(ispin), &
     624         424 :                          almo_scf_env%matrix_s_blk_sqrt(1))
     625             :          CALL dbcsr_multiply("N", "T", 1.0_dp, matrix_tmp_err, &
     626             :                              almo_scf_env%matrix_t_blk(ispin), &
     627             :                              0.0_dp, almo_scf_env%matrix_err_blk(ispin), &
     628             :                              retain_sparsity=.TRUE., &
     629         424 :                              filter_eps=eps_multiply)
     630         424 :          CALL dbcsr_release(matrix_tmp_err)
     631             :          ! bring to the orthogonal basis
     632             :          ! err_blk = (S_blk^-1/2).err_blk.(S_blk^1/2)
     633             :          CALL dbcsr_create(matrix_tmp_err, &
     634         424 :                            template=almo_scf_env%matrix_err_blk(ispin))
     635             :          CALL dbcsr_multiply("N", "N", 1.0_dp, &
     636             :                              almo_scf_env%matrix_err_blk(ispin), &
     637             :                              almo_scf_env%matrix_s_blk_sqrt(1), &
     638             :                              0.0_dp, matrix_tmp_err, &
     639         424 :                              filter_eps=eps_multiply)
     640             :          CALL dbcsr_multiply("N", "N", 1.0_dp, &
     641             :                              almo_scf_env%matrix_s_blk_sqrt_inv(1), &
     642             :                              matrix_tmp_err, &
     643             :                              0.0_dp, almo_scf_env%matrix_err_blk(ispin), &
     644         424 :                              filter_eps=eps_multiply)
     645             : 
     646             :          ! subtract transpose
     647             :          CALL dbcsr_transposed(matrix_tmp_err, &
     648         424 :                                almo_scf_env%matrix_err_blk(ispin))
     649             :          CALL dbcsr_add(almo_scf_env%matrix_err_blk(ispin), &
     650             :                         matrix_tmp_err, &
     651         424 :                         1.0_dp, -1.0_dp)
     652         424 :          CALL dbcsr_release(matrix_tmp_err)
     653             :          !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
     654             : 
     655             :          ! later we will need only the blk version of TMP6
     656             :          ! create it here and release TMP6
     657             :          !matrix_tmp9 = create OxO, blk
     658             :          !matrix_tmp9 = copy data from matrix_tmp6, retain sparsity
     659             :          !matrix_tmp6 = release
     660             :          CALL dbcsr_create(matrix_tmp9, &
     661             :                            template=almo_scf_env%matrix_sigma_blk(ispin), &
     662         424 :                            matrix_type=dbcsr_type_no_symmetry)
     663         424 :          CALL dbcsr_copy(matrix_tmp9, almo_scf_env%matrix_sigma_blk(ispin))
     664         424 :          CALL dbcsr_copy(matrix_tmp9, matrix_tmp6, keep_sparsity=.TRUE.)
     665         424 :          CALL dbcsr_release(matrix_tmp6)
     666             : 
     667             :          !10. KS_blk=KS_blk+TMP3.tr(TMP1)=
     668             :          !          =KS_blk+S.T_blk.SigInv.tr.(T_blk).KS.T_blk.SigInv.tr(T_blk).S
     669             :          !    Cost: NnO
     670             :          CALL dbcsr_multiply("N", "T", 1.0_dp, matrix_tmp3, &
     671             :                              matrix_tmp1, &
     672             :                              1.0_dp, almo_scf_env%matrix_ks_blk(ispin), &
     673             :                              retain_sparsity=.TRUE., &
     674         424 :                              filter_eps=eps_multiply)
     675             : 
     676             :          ! 11. TMP4_blk=TMP7_blk.tr(TMP8_blk)
     677             :          !    Cost: Nnn
     678             :          !matrix_tmp7 = create NxO, blk
     679             :          !matrix_tmp7 = copy data from matrix_tmp3, retain sparsity
     680             :          !matrix_tmp3 = release
     681             :          !matrix_tmp8 = create NxO, blk
     682             :          !matrix_tmp8 = copy data from matrix_tmp1, retain sparsity
     683             :          !matrix_tmp1 = release
     684             :          CALL dbcsr_create(matrix_tmp7, &
     685         424 :                            template=almo_scf_env%matrix_t_blk(ispin))
     686             :          ! transfer only the ALMO blocks from tmp3 into tmp7:
     687             :          ! first, copy t_blk into tmp7 to transfer the blk structure,
     688             :          ! then copy tmp3 into tmp7 with retain_sparsity
     689         424 :          CALL dbcsr_copy(matrix_tmp7, almo_scf_env%matrix_t_blk(ispin))
     690         424 :          CALL dbcsr_copy(matrix_tmp7, matrix_tmp3, keep_sparsity=.TRUE.)
     691         424 :          CALL dbcsr_release(matrix_tmp3)
     692             :          ! do the same for tmp1->tmp8
     693             :          CALL dbcsr_create(matrix_tmp8, &
     694         424 :                            template=almo_scf_env%matrix_t_blk(ispin))
     695         424 :          CALL dbcsr_copy(matrix_tmp8, almo_scf_env%matrix_t_blk(ispin))
     696         424 :          CALL dbcsr_copy(matrix_tmp8, matrix_tmp1, keep_sparsity=.TRUE.)
     697         424 :          CALL dbcsr_release(matrix_tmp1)
     698             :          CALL dbcsr_multiply("N", "T", 1.0_dp, matrix_tmp7, &
     699             :                              matrix_tmp8, &
     700             :                              0.0_dp, matrix_tmp4, &
     701             :                              filter_eps=eps_multiply, &
     702         424 :                              retain_sparsity=.TRUE.)
     703             : 
     704             :          ! 12. KS_blk=KS_blk-TMP4_blk
     705             :          CALL dbcsr_add(almo_scf_env%matrix_ks_blk(ispin), matrix_tmp4, &
     706         424 :                         1.0_dp, -1.0_dp)
     707             : 
     708             :          ! 13. TMP5_blk=tr(TMP5_blk)
     709             :          !     KS_blk=KS_blk-tr(TMP4_blk)
     710         424 :          CALL dbcsr_transposed(matrix_tmp5, matrix_tmp4)
     711             :          CALL dbcsr_add(almo_scf_env%matrix_ks_blk(ispin), matrix_tmp5, &
     712         424 :                         1.0_dp, -1.0_dp)
     713             : 
     714             :          ! 14. TMP4_blk=TMP7_blk.tr(TMP8_blk)
     715             :          !     Cost: Nnn
     716         424 :          CALL dbcsr_copy(matrix_tmp7, matrix_tmp2, keep_sparsity=.TRUE.)
     717         424 :          CALL dbcsr_release(matrix_tmp2)
     718             :          CALL dbcsr_multiply("N", "T", 1.0_dp, matrix_tmp7, &
     719             :                              matrix_tmp8, &
     720             :                              0.0_dp, matrix_tmp4, &
     721             :                              retain_sparsity=.TRUE., &
     722         424 :                              filter_eps=eps_multiply)
     723             :          ! 15. KS_blk=KS_blk+TMP4_blk
     724             :          CALL dbcsr_add(almo_scf_env%matrix_ks_blk(ispin), matrix_tmp4, &
     725         424 :                         1.0_dp, 1.0_dp)
     726             : 
     727             :          ! 16. KS_blk=KS_blk+tr(TMP4_blk)
     728         424 :          CALL dbcsr_transposed(matrix_tmp5, matrix_tmp4)
     729         424 :          CALL dbcsr_release(matrix_tmp4)
     730             :          CALL dbcsr_add(almo_scf_env%matrix_ks_blk(ispin), matrix_tmp5, &
     731         424 :                         1.0_dp, 1.0_dp)
     732         424 :          CALL dbcsr_release(matrix_tmp5)
     733             : 
     734             :          ! 17. TMP10_blk=TMP8_blk.TMP9_blk
     735             :          !    Cost: Noo
     736             :          CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_tmp8, &
     737             :                              matrix_tmp9, &
     738             :                              0.0_dp, matrix_tmp7, &
     739             :                              retain_sparsity=.TRUE., &
     740         424 :                              filter_eps=eps_multiply)
     741         424 :          CALL dbcsr_release(matrix_tmp9)
     742             : 
     743             :          ! 18. KS_blk=TMP7_blk.tr(TMP8_blk)
     744             :          !    Cost: Nno
     745             :          CALL dbcsr_multiply("N", "T", 1.0_dp, matrix_tmp7, &
     746             :                              matrix_tmp8, &
     747             :                              1.0_dp, almo_scf_env%matrix_ks_blk(ispin), &
     748             :                              retain_sparsity=.TRUE., &
     749         424 :                              filter_eps=eps_multiply)
     750         424 :          CALL dbcsr_release(matrix_tmp7)
     751         848 :          CALL dbcsr_release(matrix_tmp8)
     752             : 
     753             :       END DO ! spins
     754             : 
     755         424 :       CALL timestop(handle)
     756             : 
     757         424 :    END SUBROUTINE almo_scf_ks_to_ks_blk
     758             : 
     759             : ! **************************************************************************************************
     760             : !> \brief ALMOs by diagonalizing the KS domain submatrices
     761             : !>        computes both the occupied and virtual orbitals
     762             : !> \param almo_scf_env ...
     763             : !> \par History
     764             : !>       2013.03 created [Rustam Z Khaliullin]
     765             : !>       2018.09 smearing support [Ruben Staub]
     766             : !> \author Rustam Z Khaliullin
     767             : ! **************************************************************************************************
     768           2 :    SUBROUTINE almo_scf_ks_xx_to_tv_xx(almo_scf_env)
     769             : 
     770             :       TYPE(almo_scf_env_type), INTENT(INOUT)             :: almo_scf_env
     771             : 
     772             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'almo_scf_ks_xx_to_tv_xx'
     773             : 
     774             :       INTEGER                                            :: handle, iblock_size, idomain, info, &
     775             :                                                             ispin, lwork, ndomains
     776           2 :       REAL(kind=dp), ALLOCATABLE, DIMENSION(:)           :: eigenvalues, work
     777           2 :       REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :)        :: data_copy
     778             :       TYPE(domain_submatrix_type), ALLOCATABLE, &
     779           2 :          DIMENSION(:)                                    :: subm_ks_xx_orthog, subm_t, subm_tmp
     780             : 
     781           2 :       CALL timeset(routineN, handle)
     782             : 
     783           2 :       IF (almo_scf_env%domain_layout_aos == almo_domain_layout_molecular .AND. &
     784             :           almo_scf_env%mat_distr_aos == almo_mat_distr_atomic) THEN
     785           0 :          CPABORT("a domain must be located entirely on a CPU")
     786             :       END IF
     787             : 
     788           2 :       ndomains = almo_scf_env%ndomains
     789          16 :       ALLOCATE (subm_tmp(ndomains))
     790          14 :       ALLOCATE (subm_ks_xx_orthog(ndomains))
     791          14 :       ALLOCATE (subm_t(ndomains))
     792             : 
     793           4 :       DO ispin = 1, almo_scf_env%nspins
     794             : 
     795           2 :          CALL init_submatrices(subm_tmp)
     796           2 :          CALL init_submatrices(subm_ks_xx_orthog)
     797             : 
     798             :          ! TRY: project out T0-occupied space for each domain
     799             :          ! F=(1-R_du).F.(1-tr(R_du))
     800             :          !CALL copy_submatrices(almo_scf_env%domain_ks_xx(:,ispin),&
     801             :          !        subm_ks_xx_orthog,copy_data=.TRUE.)
     802             :          !CALL multiply_submatrices('N','N',1.0_dp,&
     803             :          !        almo_scf_env%domain_r_down_up(:,ispin),&
     804             :          !        almo_scf_env%domain_ks_xx(:,ispin),0.0_dp,subm_tmp)
     805             :          !CALL add_submatrices(1.0_dp,subm_ks_xx_orthog,-1.0_dp,subm_tmp,'N')
     806             :          !CALL add_submatrices(1.0_dp,subm_ks_xx_orthog,-1.0_dp,subm_tmp,'T')
     807             :          !!CALL multiply_submatrices('N','T',1.0_dp,subm_tmp,&
     808             :          !!        almo_scf_env%domain_r_down_up(:,ispin),&
     809             :          !!        1.0_dp,subm_ks_xx_orthog)
     810             : 
     811             :          ! convert blocks to the orthogonal basis set
     812             :          ! TRY: replace one multiply
     813             :          !CALL multiply_submatrices('N','N',1.0_dp,subm_ks_xx_orthog,&
     814             :          !        almo_scf_env%domain_s_sqrt_inv(:,ispin),0.0_dp,subm_tmp)
     815             :          CALL multiply_submatrices('N', 'N', 1.0_dp, almo_scf_env%domain_ks_xx(:, ispin), &
     816           2 :                                    almo_scf_env%domain_s_sqrt_inv(:, ispin), 0.0_dp, subm_tmp)
     817             :          CALL multiply_submatrices('N', 'N', 1.0_dp, almo_scf_env%domain_s_sqrt_inv(:, ispin), &
     818           2 :                                    subm_tmp, 0.0_dp, subm_ks_xx_orthog)
     819           2 :          CALL release_submatrices(subm_tmp)
     820             : 
     821             :          ! create temporary matrices for occupied and virtual orbitals
     822             :          ! represented in the orthogonalized basis set
     823           2 :          CALL init_submatrices(subm_t)
     824             : 
     825             :          ! loop over domains - perform diagonalization
     826          12 :          DO idomain = 1, ndomains
     827             : 
     828             :             ! check if the submatrix exists
     829          12 :             IF (subm_ks_xx_orthog(idomain)%domain .GT. 0) THEN
     830             : 
     831           5 :                iblock_size = subm_ks_xx_orthog(idomain)%nrows
     832             : 
     833             :                ! Prepare data
     834          15 :                ALLOCATE (eigenvalues(iblock_size))
     835          20 :                ALLOCATE (data_copy(iblock_size, iblock_size))
     836       31607 :                data_copy(:, :) = subm_ks_xx_orthog(idomain)%mdata(:, :)
     837             : 
     838             :                ! Query the optimal workspace for dsyev
     839           5 :                LWORK = -1
     840           5 :                ALLOCATE (WORK(MAX(1, LWORK)))
     841           5 :                CALL dsyev('V', 'L', iblock_size, data_copy, iblock_size, eigenvalues, WORK, LWORK, INFO)
     842           5 :                LWORK = INT(WORK(1))
     843           5 :                DEALLOCATE (WORK)
     844             : 
     845             :                ! Allocate the workspace and solve the eigenproblem
     846          15 :                ALLOCATE (WORK(MAX(1, LWORK)))
     847           5 :                CALL dsyev('V', 'L', iblock_size, data_copy, iblock_size, eigenvalues, WORK, LWORK, INFO)
     848           5 :                IF (INFO .NE. 0) CPABORT("DSYEV failed")
     849             : 
     850             :                ! Copy occupied eigenvectors
     851           5 :                IF (almo_scf_env%domain_t(idomain, ispin)%ncols .NE. &
     852             :                    almo_scf_env%nocc_of_domain(idomain, ispin)) THEN
     853           0 :                   CPABORT("wrong domain structure")
     854             :                END IF
     855             :                CALL copy_submatrices(almo_scf_env%domain_t(idomain, ispin), &
     856           5 :                                      subm_t(idomain), .FALSE.)
     857             :                CALL copy_submatrix_data(data_copy(:, 1:almo_scf_env%nocc_of_domain(idomain, ispin)), &
     858           5 :                                         subm_t(idomain))
     859             :                !! Copy occupied eigenvalues if smearing requested
     860           5 :                IF (almo_scf_env%smear) THEN
     861             :                   almo_scf_env%mo_energies(1 + SUM(almo_scf_env%nocc_of_domain(:idomain - 1, ispin)) &
     862             :                                            :SUM(almo_scf_env%nocc_of_domain(:idomain, ispin)), ispin) &
     863           0 :                      = eigenvalues(1:almo_scf_env%nocc_of_domain(idomain, ispin))
     864             :                END IF
     865             : 
     866           5 :                DEALLOCATE (WORK)
     867           5 :                DEALLOCATE (data_copy)
     868           5 :                DEALLOCATE (eigenvalues)
     869             : 
     870             :             END IF ! submatrix for the domain exists
     871             : 
     872             :          END DO ! loop over domains
     873             : 
     874           2 :          CALL release_submatrices(subm_ks_xx_orthog)
     875             : 
     876             :          ! convert orbitals to the AO basis set (from orthogonalized AOs)
     877             :          CALL multiply_submatrices('N', 'N', 1.0_dp, almo_scf_env%domain_s_sqrt_inv(:, ispin), &
     878           2 :                                    subm_t, 0.0_dp, almo_scf_env%domain_t(:, ispin))
     879           2 :          CALL release_submatrices(subm_t)
     880             : 
     881             :          ! convert domain orbitals to a dbcsr matrix
     882             :          CALL construct_dbcsr_from_submatrices( &
     883             :             almo_scf_env%matrix_t(ispin), &
     884             :             almo_scf_env%domain_t(:, ispin), &
     885           2 :             almo_scf_env%quench_t(ispin))
     886             :          CALL dbcsr_filter(almo_scf_env%matrix_t(ispin), &
     887           4 :                            almo_scf_env%eps_filter)
     888             : 
     889             :          ! TRY: add T0 component
     890             :          !!CALL dbcsr_add(almo_scf_env%matrix_t(ispin),&
     891             :          !!        almo_scf_env%matrix_t_blk(ispin),1.0_dp,1.0_dp)
     892             : 
     893             :       END DO ! spins
     894             : 
     895          12 :       DEALLOCATE (subm_tmp)
     896          12 :       DEALLOCATE (subm_ks_xx_orthog)
     897          12 :       DEALLOCATE (subm_t)
     898             : 
     899           2 :       CALL timestop(handle)
     900             : 
     901           4 :    END SUBROUTINE almo_scf_ks_xx_to_tv_xx
     902             : 
     903             : ! **************************************************************************************************
     904             : !> \brief computes ALMOs by diagonalizing the projected blocked KS matrix
     905             : !>        uses the diagonalization code for blocks
     906             : !>        computes both the occupied and virtual orbitals
     907             : !> \param almo_scf_env ...
     908             : !> \par History
     909             : !>       2011.07 created [Rustam Z Khaliullin]
     910             : !>       2018.09 smearing support [Ruben Staub]
     911             : !> \author Rustam Z Khaliullin
     912             : ! **************************************************************************************************
     913         348 :    SUBROUTINE almo_scf_ks_blk_to_tv_blk(almo_scf_env)
     914             : 
     915             :       TYPE(almo_scf_env_type), INTENT(INOUT)             :: almo_scf_env
     916             : 
     917             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'almo_scf_ks_blk_to_tv_blk'
     918             : 
     919             :       INTEGER                                            :: handle, iblock_col, iblock_row, &
     920             :                                                             iblock_size, info, ispin, lwork, &
     921             :                                                             nocc_of_block, nvirt_of_block, orbital
     922             :       LOGICAL                                            :: block_needed
     923         348 :       REAL(kind=dp), ALLOCATABLE, DIMENSION(:)           :: eigenvalues, work
     924         348 :       REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :)        :: data_copy
     925         348 :       REAL(kind=dp), DIMENSION(:, :), POINTER            :: data_p, p_new_block
     926             :       TYPE(dbcsr_iterator_type)                          :: iter
     927             :       TYPE(dbcsr_type)                                   :: matrix_ks_blk_orthog, &
     928             :                                                             matrix_t_blk_orthog, matrix_tmp, &
     929             :                                                             matrix_v_blk_orthog
     930             : 
     931         348 :       CALL timeset(routineN, handle)
     932             : 
     933         348 :       IF (almo_scf_env%domain_layout_aos == almo_domain_layout_molecular .AND. &
     934             :           almo_scf_env%mat_distr_aos == almo_mat_distr_atomic) THEN
     935           0 :          CPABORT("a domain must be located entirely on a CPU")
     936             :       END IF
     937             : 
     938         696 :       DO ispin = 1, almo_scf_env%nspins
     939             : 
     940             :          CALL dbcsr_create(matrix_tmp, template=almo_scf_env%matrix_ks_blk(ispin), &
     941         348 :                            matrix_type=dbcsr_type_no_symmetry)
     942             :          CALL dbcsr_create(matrix_ks_blk_orthog, template=almo_scf_env%matrix_ks_blk(ispin), &
     943         348 :                            matrix_type=dbcsr_type_no_symmetry)
     944             : 
     945             :          ! convert blocks to the orthogonal basis set
     946             :          CALL dbcsr_multiply("N", "N", 1.0_dp, almo_scf_env%matrix_ks_blk(ispin), &
     947             :                              almo_scf_env%matrix_s_blk_sqrt_inv(1), 0.0_dp, matrix_tmp, &
     948         348 :                              filter_eps=almo_scf_env%eps_filter)
     949             :          CALL dbcsr_multiply("N", "N", 1.0_dp, almo_scf_env%matrix_s_blk_sqrt_inv(1), &
     950             :                              matrix_tmp, 0.0_dp, matrix_ks_blk_orthog, &
     951         348 :                              filter_eps=almo_scf_env%eps_filter)
     952             : 
     953         348 :          CALL dbcsr_release(matrix_tmp)
     954             : 
     955             :          ! create temporary matrices for occupied and virtual orbitals
     956             :          ! represented in the orthogonalized AOs basis set
     957         348 :          CALL dbcsr_create(matrix_t_blk_orthog, template=almo_scf_env%matrix_t_blk(ispin))
     958         348 :          CALL dbcsr_create(matrix_v_blk_orthog, template=almo_scf_env%matrix_v_full_blk(ispin))
     959         348 :          CALL dbcsr_work_create(matrix_t_blk_orthog, work_mutable=.TRUE.)
     960         348 :          CALL dbcsr_work_create(matrix_v_blk_orthog, work_mutable=.TRUE.)
     961             : 
     962         348 :          CALL dbcsr_work_create(almo_scf_env%matrix_eoo(ispin), work_mutable=.TRUE.)
     963         348 :          CALL dbcsr_work_create(almo_scf_env%matrix_evv_full(ispin), work_mutable=.TRUE.)
     964             : 
     965         348 :          CALL dbcsr_iterator_start(iter, matrix_ks_blk_orthog)
     966             : 
     967        1624 :          DO WHILE (dbcsr_iterator_blocks_left(iter))
     968        1276 :             CALL dbcsr_iterator_next_block(iter, iblock_row, iblock_col, data_p, row_size=iblock_size)
     969             : 
     970        1276 :             IF (iblock_row .NE. iblock_col) THEN
     971           0 :                CPABORT("off-diagonal block found")
     972             :             END IF
     973             : 
     974        1276 :             block_needed = .TRUE.
     975        1276 :             IF (almo_scf_env%nocc_of_domain(iblock_col, ispin) .EQ. 0 .AND. &
     976             :                 almo_scf_env%nvirt_of_domain(iblock_col, ispin) .EQ. 0) THEN
     977             :                block_needed = .FALSE.
     978             :             END IF
     979             : 
     980         348 :             IF (block_needed) THEN
     981             : 
     982             :                ! Prepare data
     983        3828 :                ALLOCATE (eigenvalues(iblock_size))
     984        5104 :                ALLOCATE (data_copy(iblock_size, iblock_size))
     985      382688 :                data_copy(:, :) = data_p(:, :)
     986             : 
     987             :                ! Query the optimal workspace for dsyev
     988        1276 :                LWORK = -1
     989        1276 :                ALLOCATE (WORK(MAX(1, LWORK)))
     990        1276 :                CALL dsyev('V', 'L', iblock_size, data_copy, iblock_size, eigenvalues, WORK, LWORK, INFO)
     991        1276 :                LWORK = INT(WORK(1))
     992        1276 :                DEALLOCATE (WORK)
     993             : 
     994             :                ! Allocate the workspace and solve the eigenproblem
     995        3828 :                ALLOCATE (WORK(MAX(1, LWORK)))
     996        1276 :                CALL dsyev('V', 'L', iblock_size, data_copy, iblock_size, eigenvalues, WORK, LWORK, INFO)
     997        1276 :                IF (INFO .NE. 0) CPABORT("DSYEV failed")
     998             : 
     999             :                !!! RZK-warning                                               !!!
    1000             :                !!! IT IS EXTREMELY IMPORTANT THAT THE DIAGONAL BLOCKS OF THE !!!
    1001             :                !!! FOLLOWING MATRICES ARE LOCATED ON THE SAME NODES WITH     !!!
    1002             :                !!! THE CORRESPONDING DIAGONAL BLOCKS OF THE FOCK MATRIX:     !!!
    1003             :                !!! T, V, E_o, E_v
    1004             : 
    1005             :                ! copy eigenvectors into two dbcsr matrices - occupied and virtuals
    1006        1276 :                nocc_of_block = almo_scf_env%nocc_of_domain(iblock_col, ispin)
    1007        1276 :                IF (nocc_of_block .GT. 0) THEN
    1008        1252 :                   NULLIFY (p_new_block)
    1009        1252 :                   CALL dbcsr_reserve_block2d(matrix_t_blk_orthog, iblock_row, iblock_col, p_new_block)
    1010        1252 :                   CPASSERT(ASSOCIATED(p_new_block))
    1011       90468 :                   p_new_block(:, :) = data_copy(:, 1:nocc_of_block)
    1012             :                   ! copy eigenvalues into diagonal dbcsr matrix - Eoo
    1013        1252 :                   NULLIFY (p_new_block)
    1014        1252 :                   CALL dbcsr_reserve_block2d(almo_scf_env%matrix_eoo(ispin), iblock_row, iblock_col, p_new_block)
    1015        1252 :                   CPASSERT(ASSOCIATED(p_new_block))
    1016       32156 :                   p_new_block(:, :) = 0.0_dp
    1017        6358 :                   DO orbital = 1, nocc_of_block
    1018        6358 :                      p_new_block(orbital, orbital) = eigenvalues(orbital)
    1019             :                   END DO
    1020             :                   !! Retrieve occupied MOs energies for smearing purpose, if requested
    1021             :                   !! RS-WARNING: Hack to retrieve the occupied energies, since matrix_eoo seems to be ill-defined
    1022             :                   !!             for multiprocessing (any idea for fix?)
    1023             :                   !! RS-WARNING: This section is not suitable for parallel run !!!
    1024             :                   !!             (but usually fails less than retrieving the diagonal of matrix_eoo)
    1025             :                   !! RS-WARNING: This method will likely keep the energies of the initial guess if run in parallel
    1026             :                   !!             (which is still a reasonable smearing in most cases...)
    1027        1252 :                   IF (almo_scf_env%smear) THEN
    1028         292 :                      DO orbital = 1, nocc_of_block
    1029             :                         almo_scf_env%mo_energies(SUM(almo_scf_env%nocc_of_domain(:iblock_row - 1, ispin)) + orbital, &
    1030         348 :                                                  ispin) = eigenvalues(orbital)
    1031             :                      END DO
    1032             :                   END IF
    1033             :                END IF
    1034             : 
    1035             :                ! now virtuals
    1036        1276 :                nvirt_of_block = almo_scf_env%nvirt_of_domain(iblock_col, ispin)
    1037        1276 :                IF (nvirt_of_block .GT. 0) THEN
    1038        1276 :                   NULLIFY (p_new_block)
    1039        1276 :                   CALL dbcsr_reserve_block2d(matrix_v_blk_orthog, iblock_row, iblock_col, p_new_block)
    1040        1276 :                   CPASSERT(ASSOCIATED(p_new_block))
    1041      293472 :                   p_new_block(:, :) = data_copy(:, (nocc_of_block + 1):(nocc_of_block + nvirt_of_block))
    1042             :                   ! virtual energies
    1043        1276 :                   NULLIFY (p_new_block)
    1044        1276 :                   CALL dbcsr_reserve_block2d(almo_scf_env%matrix_evv_full(ispin), iblock_row, iblock_col, p_new_block)
    1045        1276 :                   CPASSERT(ASSOCIATED(p_new_block))
    1046      235160 :                   p_new_block(:, :) = 0.0_dp
    1047       13896 :                   DO orbital = 1, nvirt_of_block
    1048       13896 :                      p_new_block(orbital, orbital) = eigenvalues(nocc_of_block + orbital)
    1049             :                   END DO
    1050             :                END IF
    1051             : 
    1052        1276 :                DEALLOCATE (WORK)
    1053        1276 :                DEALLOCATE (data_copy)
    1054        1276 :                DEALLOCATE (eigenvalues)
    1055             : 
    1056             :             END IF
    1057             : 
    1058             :          END DO
    1059         348 :          CALL dbcsr_iterator_stop(iter)
    1060             : 
    1061         348 :          CALL dbcsr_finalize(matrix_t_blk_orthog)
    1062         348 :          CALL dbcsr_finalize(matrix_v_blk_orthog)
    1063         348 :          CALL dbcsr_finalize(almo_scf_env%matrix_eoo(ispin))
    1064         348 :          CALL dbcsr_finalize(almo_scf_env%matrix_evv_full(ispin))
    1065             : 
    1066             :          !! RS-WARNING: When matrix_eoo will be well-defined with multiprocessing,
    1067             :          !!             the following should be the preferred way to retrieve the occupied energies:
    1068             :          !! Retrieve occupied MOs energies for smearing purpose, if requested
    1069             :          !! IF (almo_scf_env%smear) THEN
    1070             :          !!    CALL dbcsr_get_diag(almo_scf_env%matrix_eoo(ispin), almo_scf_env%mo_energies(:, ispin))
    1071             :          !! END IF
    1072             : 
    1073         348 :          CALL dbcsr_filter(matrix_t_blk_orthog, almo_scf_env%eps_filter)
    1074         348 :          CALL dbcsr_filter(matrix_v_blk_orthog, almo_scf_env%eps_filter)
    1075             : 
    1076         348 :          CALL dbcsr_release(matrix_ks_blk_orthog)
    1077             : 
    1078             :          ! convert orbitals to the AO basis set (from orthogonalized AOs)
    1079             :          CALL dbcsr_multiply("N", "N", 1.0_dp, almo_scf_env%matrix_s_blk_sqrt_inv(1), &
    1080             :                              matrix_t_blk_orthog, 0.0_dp, almo_scf_env%matrix_t_blk(ispin), &
    1081         348 :                              filter_eps=almo_scf_env%eps_filter)
    1082             :          CALL dbcsr_multiply("N", "N", 1.0_dp, almo_scf_env%matrix_s_blk_sqrt_inv(1), &
    1083             :                              matrix_v_blk_orthog, 0.0_dp, almo_scf_env%matrix_v_full_blk(ispin), &
    1084         348 :                              filter_eps=almo_scf_env%eps_filter)
    1085             : 
    1086         348 :          CALL dbcsr_release(matrix_t_blk_orthog)
    1087        1044 :          CALL dbcsr_release(matrix_v_blk_orthog)
    1088             : 
    1089             :       END DO ! spins
    1090             : 
    1091         348 :       CALL timestop(handle)
    1092             : 
    1093         696 :    END SUBROUTINE almo_scf_ks_blk_to_tv_blk
    1094             : 
    1095             : ! **************************************************************************************************
    1096             : !> \brief inverts block-diagonal blocks of a dbcsr_matrix
    1097             : !> \param matrix_in ...
    1098             : !> \param matrix_out ...
    1099             : !> \param nocc ...
    1100             : !> \par History
    1101             : !>       2012.05 created [Rustam Z Khaliullin]
    1102             : !> \author Rustam Z Khaliullin
    1103             : ! **************************************************************************************************
    1104          82 :    SUBROUTINE pseudo_invert_diagonal_blk(matrix_in, matrix_out, nocc)
    1105             : 
    1106             :       TYPE(dbcsr_type), INTENT(IN)                       :: matrix_in
    1107             :       TYPE(dbcsr_type), INTENT(INOUT)                    :: matrix_out
    1108             :       INTEGER, DIMENSION(:)                              :: nocc
    1109             : 
    1110             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'pseudo_invert_diagonal_blk'
    1111             : 
    1112             :       INTEGER                                            :: handle, iblock_col, iblock_row, &
    1113             :                                                             iblock_size, methodID
    1114          82 :       REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :)        :: data_copy
    1115          82 :       REAL(kind=dp), DIMENSION(:, :), POINTER            :: data_p, p_new_block
    1116             :       TYPE(dbcsr_iterator_type)                          :: iter
    1117             : 
    1118          82 :       CALL timeset(routineN, handle)
    1119             : 
    1120          82 :       CALL dbcsr_create(matrix_out, template=matrix_in)
    1121          82 :       CALL dbcsr_work_create(matrix_out, work_mutable=.TRUE.)
    1122             : 
    1123          82 :       CALL dbcsr_iterator_start(iter, matrix_in)
    1124             : 
    1125         423 :       DO WHILE (dbcsr_iterator_blocks_left(iter))
    1126             : 
    1127         341 :          CALL dbcsr_iterator_next_block(iter, iblock_row, iblock_col, data_p, row_size=iblock_size)
    1128             : 
    1129         423 :          IF (iblock_row == iblock_col) THEN
    1130             : 
    1131             :             ! Prepare data
    1132        1276 :             ALLOCATE (data_copy(iblock_size, iblock_size))
    1133             :             !data_copy(:,:)=data_p(:,:)
    1134             : 
    1135             :             ! 0. Cholesky factorization
    1136             :             ! 1. Diagonalization
    1137         319 :             methodID = 1
    1138             :             CALL pseudo_invert_matrix(data_p, data_copy, iblock_size, &
    1139             :                                       methodID, &
    1140             :                                       range1=nocc(iblock_row), range2=nocc(iblock_row), &
    1141             :                                       !range1_thr,range2_thr,&
    1142         319 :                                       shift=1.0E-5_dp)
    1143             :             !!! IT IS EXTREMELY IMPORTANT THAT THE BLOCKS OF THE "OUT"  !!!
    1144             :             !!! MATRIX ARE DISTRIBUTED AS THE BLOCKS OF THE "IN" MATRIX !!!
    1145             : 
    1146         319 :             NULLIFY (p_new_block)
    1147         319 :             CALL dbcsr_reserve_block2d(matrix_out, iblock_row, iblock_col, p_new_block)
    1148         319 :             CPASSERT(ASSOCIATED(p_new_block))
    1149      221823 :             p_new_block(:, :) = data_copy(:, :)
    1150             : 
    1151         319 :             DEALLOCATE (data_copy)
    1152             : 
    1153             :          END IF
    1154             : 
    1155             :       END DO
    1156          82 :       CALL dbcsr_iterator_stop(iter)
    1157             : 
    1158          82 :       CALL dbcsr_finalize(matrix_out)
    1159             : 
    1160          82 :       CALL timestop(handle)
    1161             : 
    1162         164 :    END SUBROUTINE pseudo_invert_diagonal_blk
    1163             : 
    1164             : ! **************************************************************************************************
    1165             : !> \brief computes occupied ALMOs from the superimposed atomic density blocks
    1166             : !> \param almo_scf_env ...
    1167             : !> \param ionic ...
    1168             : !> \par History
    1169             : !>       2011.06 created [Rustam Z Khaliullin]
    1170             : !> \author Rustam Z Khaliullin
    1171             : ! **************************************************************************************************
    1172          60 :    SUBROUTINE almo_scf_p_blk_to_t_blk(almo_scf_env, ionic)
    1173             : 
    1174             :       TYPE(almo_scf_env_type), INTENT(INOUT)             :: almo_scf_env
    1175             :       LOGICAL, INTENT(IN)                                :: ionic
    1176             : 
    1177             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'almo_scf_p_blk_to_t_blk'
    1178             : 
    1179             :       INTEGER                                            :: handle, iblock_col, iblock_row, &
    1180             :                                                             iblock_size, info, ispin, lwork, &
    1181             :                                                             nocc_of_block, unit_nr
    1182             :       LOGICAL                                            :: block_needed
    1183          60 :       REAL(kind=dp), ALLOCATABLE, DIMENSION(:)           :: eigenvalues, work
    1184          60 :       REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :)        :: data_copy
    1185          60 :       REAL(kind=dp), DIMENSION(:, :), POINTER            :: data_p, p_new_block
    1186             :       TYPE(cp_logger_type), POINTER                      :: logger
    1187             :       TYPE(dbcsr_iterator_type)                          :: iter
    1188             :       TYPE(dbcsr_type)                                   :: matrix_t_blk_tmp
    1189             : 
    1190          60 :       CALL timeset(routineN, handle)
    1191             : 
    1192             :       ! get a useful unit_nr
    1193          60 :       logger => cp_get_default_logger()
    1194          60 :       IF (logger%para_env%is_source()) THEN
    1195          30 :          unit_nr = cp_logger_get_default_unit_nr(logger, local=.TRUE.)
    1196             :       ELSE
    1197             :          unit_nr = -1
    1198             :       END IF
    1199             : 
    1200         120 :       DO ispin = 1, almo_scf_env%nspins
    1201             : 
    1202         120 :          IF (ionic) THEN
    1203             : 
    1204             :             ! create a temporary matrix to keep the eigenvectors
    1205             :             CALL dbcsr_create(matrix_t_blk_tmp, &
    1206           0 :                               template=almo_scf_env%matrix_t_blk(ispin))
    1207             :             CALL dbcsr_work_create(matrix_t_blk_tmp, &
    1208           0 :                                    work_mutable=.TRUE.)
    1209             : 
    1210           0 :             CALL dbcsr_iterator_start(iter, almo_scf_env%matrix_p_blk(ispin))
    1211           0 :             DO WHILE (dbcsr_iterator_blocks_left(iter))
    1212           0 :                CALL dbcsr_iterator_next_block(iter, iblock_row, iblock_col, data_p, row_size=iblock_size)
    1213             : 
    1214           0 :                block_needed = .FALSE.
    1215             : 
    1216           0 :                IF (iblock_row == iblock_col) THEN
    1217             :                   block_needed = .TRUE.
    1218             :                END IF
    1219             : 
    1220             :                IF (.NOT. block_needed) THEN
    1221           0 :                   CPABORT("off-diag block found")
    1222             :                END IF
    1223             : 
    1224             :                ! Prepare data
    1225           0 :                ALLOCATE (eigenvalues(iblock_size))
    1226           0 :                ALLOCATE (data_copy(iblock_size, iblock_size))
    1227           0 :                data_copy(:, :) = data_p(:, :)
    1228             : 
    1229             :                ! Query the optimal workspace for dsyev
    1230           0 :                LWORK = -1
    1231           0 :                ALLOCATE (WORK(MAX(1, LWORK)))
    1232             :                CALL dsyev('V', 'L', iblock_size, data_copy, iblock_size, eigenvalues, &
    1233           0 :                           WORK, LWORK, INFO)
    1234           0 :                LWORK = INT(WORK(1))
    1235           0 :                DEALLOCATE (WORK)
    1236             : 
    1237             :                ! Allocate the workspace and solve the eigenproblem
    1238           0 :                ALLOCATE (WORK(MAX(1, LWORK)))
    1239           0 :                CALL dsyev('V', 'L', iblock_size, data_copy, iblock_size, eigenvalues, WORK, LWORK, INFO)
    1240           0 :                IF (INFO .NE. 0) THEN
    1241           0 :                   IF (unit_nr > 0) THEN
    1242           0 :                      WRITE (unit_nr, *) 'BLOCK  = ', iblock_row
    1243           0 :                      WRITE (unit_nr, *) 'INFO   =', INFO
    1244           0 :                      WRITE (unit_nr, *) data_p(:, :)
    1245             :                   END IF
    1246           0 :                   CPABORT("DSYEV failed")
    1247             :                END IF
    1248             : 
    1249             :                !!! IT IS EXTREMELY IMPORTANT THAT THE DIAGONAL BLOCKS OF THE !!!
    1250             :                !!! P AND T MATRICES ARE LOCATED ON THE SAME NODES            !!!
    1251             : 
    1252             :                ! copy eigenvectors into two dbcsr matrices - occupied and virtuals
    1253           0 :                NULLIFY (p_new_block)
    1254             :                CALL dbcsr_reserve_block2d(matrix_t_blk_tmp, &
    1255           0 :                                           iblock_row, iblock_col, p_new_block)
    1256           0 :                nocc_of_block = SIZE(p_new_block, 2)
    1257           0 :                CPASSERT(ASSOCIATED(p_new_block))
    1258           0 :                CPASSERT(nocc_of_block .GT. 0)
    1259           0 :                p_new_block(:, :) = data_copy(:, iblock_size - nocc_of_block + 1:)
    1260             : 
    1261           0 :                DEALLOCATE (WORK)
    1262           0 :                DEALLOCATE (data_copy)
    1263           0 :                DEALLOCATE (eigenvalues)
    1264             : 
    1265             :             END DO
    1266           0 :             CALL dbcsr_iterator_stop(iter)
    1267             : 
    1268           0 :             CALL dbcsr_finalize(matrix_t_blk_tmp)
    1269             :             CALL dbcsr_filter(matrix_t_blk_tmp, &
    1270           0 :                               almo_scf_env%eps_filter)
    1271             :             CALL dbcsr_copy(almo_scf_env%matrix_t_blk(ispin), &
    1272           0 :                             matrix_t_blk_tmp)
    1273           0 :             CALL dbcsr_release(matrix_t_blk_tmp)
    1274             : 
    1275             :          ELSE
    1276             : 
    1277             :             !! generate a random set of ALMOs
    1278             :             !! matrix_t_blk should already be initiated to the proper domain structure
    1279             :             CALL dbcsr_init_random(almo_scf_env%matrix_t_blk(ispin), &
    1280          60 :                                    keep_sparsity=.TRUE.)
    1281             : 
    1282             :             CALL dbcsr_create(matrix_t_blk_tmp, &
    1283             :                               template=almo_scf_env%matrix_t_blk(ispin), &
    1284          60 :                               matrix_type=dbcsr_type_no_symmetry)
    1285             : 
    1286             :             ! use current ALMOs in matrix_t_blk and project them onto the blocked dm
    1287             :             ! compute T_new = R_blk S_blk T_random
    1288             :             CALL dbcsr_multiply("N", "N", 1.0_dp, almo_scf_env%matrix_s_blk(1), &
    1289             :                                 almo_scf_env%matrix_t_blk(ispin), &
    1290             :                                 0.0_dp, matrix_t_blk_tmp, &
    1291          60 :                                 filter_eps=almo_scf_env%eps_filter)
    1292             : 
    1293             :             CALL dbcsr_multiply("N", "N", 1.0_dp, &
    1294             :                                 almo_scf_env%matrix_p_blk(ispin), matrix_t_blk_tmp, &
    1295             :                                 0.0_dp, almo_scf_env%matrix_t_blk(ispin), &
    1296          60 :                                 filter_eps=almo_scf_env%eps_filter)
    1297             : 
    1298          60 :             CALL dbcsr_release(matrix_t_blk_tmp)
    1299             : 
    1300             :          END IF
    1301             : 
    1302             :       END DO
    1303             : 
    1304          60 :       CALL timestop(handle)
    1305             : 
    1306         120 :    END SUBROUTINE almo_scf_p_blk_to_t_blk
    1307             : 
    1308             : ! **************************************************************************************************
    1309             : !> \brief Apply an occupation-rescaling trick to ALMOs for smearing.
    1310             : !>        Partially occupied orbitals are considered full and rescaled by SQRT(occupation_number)
    1311             : !>        (this was designed to be used with smearing only)
    1312             : !> \param matrix_t ...
    1313             : !> \param mo_energies ...
    1314             : !> \param mu_of_domain ...
    1315             : !> \param real_ne_of_domain ...
    1316             : !> \param spin_kTS ...
    1317             : !> \param smear_e_temp ...
    1318             : !> \param ndomains ...
    1319             : !> \param nocc_of_domain ...
    1320             : !> \par History
    1321             : !>       2018.09 created [Ruben Staub]
    1322             : !> \author Ruben Staub
    1323             : ! **************************************************************************************************
    1324          40 :    SUBROUTINE almo_scf_t_rescaling(matrix_t, mo_energies, mu_of_domain, real_ne_of_domain, &
    1325          20 :                                    spin_kTS, smear_e_temp, ndomains, nocc_of_domain)
    1326             : 
    1327             :       TYPE(dbcsr_type), INTENT(INOUT)                    :: matrix_t
    1328             :       REAL(KIND=dp), DIMENSION(:), INTENT(IN)            :: mo_energies
    1329             :       REAL(KIND=dp), DIMENSION(:), INTENT(INOUT)         :: mu_of_domain, real_ne_of_domain
    1330             :       REAL(KIND=dp), INTENT(INOUT)                       :: spin_kTS
    1331             :       REAL(KIND=dp), INTENT(IN)                          :: smear_e_temp
    1332             :       INTEGER, INTENT(IN)                                :: ndomains
    1333             :       INTEGER, DIMENSION(:), INTENT(IN)                  :: nocc_of_domain
    1334             : 
    1335             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'almo_scf_t_rescaling'
    1336             : 
    1337             :       INTEGER                                            :: handle, idomain, neigenval_used, nmo
    1338             :       REAL(KIND=dp)                                      :: kTS
    1339          20 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: occupation_numbers, rescaling_factors
    1340             : 
    1341          20 :       CALL timeset(routineN, handle)
    1342             : 
    1343             :       !!
    1344             :       !! Initialization
    1345             :       !!
    1346          20 :       nmo = SIZE(mo_energies)
    1347          60 :       ALLOCATE (occupation_numbers(nmo))
    1348          40 :       ALLOCATE (rescaling_factors(nmo))
    1349             : 
    1350             :       !!
    1351             :       !! Set occupation numbers for smearing
    1352             :       !!
    1353             :       !! occupation numbers are obtained using Fermi-Dirac smearing with orbital energies stored in mo_energies
    1354             :       !! nocc_of_domain is the number of partially occupied orbitals, while real_ne_of_domain is the real number of electrons
    1355          20 :       neigenval_used = 0 !! this is used as an offset to copy sub-arrays
    1356             : 
    1357             :       !! Reset electronic entropy term
    1358          20 :       spin_kTS = 0.0_dp
    1359             : 
    1360             :       !! Apply Fermi-Dirac smearing for each domain and store associated occupations for the whole system
    1361          60 :       DO idomain = 1, ndomains
    1362             :          CALL FermiFixed(occupation_numbers(1 + neigenval_used:nocc_of_domain(idomain) + neigenval_used), &
    1363             :                          mu_of_domain(idomain), &
    1364             :                          kTS, &
    1365             :                          mo_energies(1 + neigenval_used:nocc_of_domain(idomain) + neigenval_used), &
    1366             :                          real_ne_of_domain(idomain), &
    1367             :                          smear_e_temp, &
    1368          40 :                          1.0_dp) !! Warning, maxocc is set to 1 since we don't want to interfere with the spin_factor rescaling
    1369          40 :          spin_kTS = spin_kTS + kTS !! Add up electronic entropy contributions
    1370          60 :          neigenval_used = neigenval_used + nocc_of_domain(idomain) !! Update eigenvalues index offset
    1371             :       END DO
    1372         700 :       rescaling_factors(:) = SQRT(occupation_numbers) !! scale = sqrt(occupation_number)
    1373             : 
    1374             :       !!
    1375             :       !! Rescaling electronic entropy contribution by spin_factor (deprecated)
    1376             :       !! (currently, entropy is rescaled by spin_factor with the density matrix)
    1377             :       !!
    1378             :       !!IF (almo_scf_env%nspins == 1) THEN
    1379             :       !!   spin_kTS = spin_kTS*2.0_dp
    1380             :       !!END IF
    1381             : 
    1382             :       !!
    1383             :       !! Rescaling of T (i.e. ALMOs)
    1384             :       !!
    1385          20 :       CALL dbcsr_scale_by_vector(matrix_t, rescaling_factors, side='right') !! Apply occupation-rescaling trick
    1386             : 
    1387             :       !!
    1388             :       !! Debug tools (for debug purpose only)
    1389             :       !!
    1390             :       !! WRITE (*,*) "occupations", occupation_numbers(:) !! debug
    1391             :       !! WRITE (*,*) "eigenvalues", mo_energies(:) !! debug
    1392             :       !! WRITE (*,*) "kTS (spin_factor excluded) = ", spin_kTS !! debug
    1393             : 
    1394             :       !!
    1395             :       !! Cleaning up before exit
    1396             :       !!
    1397          20 :       DEALLOCATE (occupation_numbers)
    1398          20 :       DEALLOCATE (rescaling_factors)
    1399             : 
    1400          20 :       CALL timestop(handle)
    1401             : 
    1402          40 :    END SUBROUTINE almo_scf_t_rescaling
    1403             : 
    1404             : ! **************************************************************************************************
    1405             : !> \brief Computes the overlap matrix of MO orbitals
    1406             : !> \param bra ...
    1407             : !> \param ket ...
    1408             : !> \param overlap ...
    1409             : !> \param metric ...
    1410             : !> \param retain_overlap_sparsity ...
    1411             : !> \param eps_filter ...
    1412             : !> \param smear ...
    1413             : !> \par History
    1414             : !>       2011.08 created [Rustam Z Khaliullin]
    1415             : !>       2018.09 smearing support [Ruben Staub]
    1416             : !> \author Rustam Z Khaliullin
    1417             : ! **************************************************************************************************
    1418         378 :    SUBROUTINE get_overlap(bra, ket, overlap, metric, retain_overlap_sparsity, &
    1419             :                           eps_filter, smear)
    1420             : 
    1421             :       TYPE(dbcsr_type), INTENT(IN)                       :: bra, ket
    1422             :       TYPE(dbcsr_type), INTENT(INOUT)                    :: overlap
    1423             :       TYPE(dbcsr_type), INTENT(IN)                       :: metric
    1424             :       LOGICAL, INTENT(IN), OPTIONAL                      :: retain_overlap_sparsity
    1425             :       REAL(KIND=dp)                                      :: eps_filter
    1426             :       LOGICAL, INTENT(IN), OPTIONAL                      :: smear
    1427             : 
    1428             :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'get_overlap'
    1429             : 
    1430             :       INTEGER                                            :: dim0, handle
    1431             :       LOGICAL                                            :: local_retain_sparsity, smearing
    1432         378 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: diag_correction
    1433             :       TYPE(dbcsr_type)                                   :: tmp
    1434             : 
    1435         378 :       CALL timeset(routineN, handle)
    1436             : 
    1437         378 :       IF (.NOT. PRESENT(retain_overlap_sparsity)) THEN
    1438           0 :          local_retain_sparsity = .FALSE.
    1439             :       ELSE
    1440         378 :          local_retain_sparsity = retain_overlap_sparsity
    1441             :       END IF
    1442             : 
    1443         378 :       IF (.NOT. PRESENT(smear)) THEN
    1444             :          smearing = .FALSE.
    1445             :       ELSE
    1446         378 :          smearing = smear
    1447             :       END IF
    1448             : 
    1449             :       CALL dbcsr_create(tmp, template=ket, &
    1450         378 :                         matrix_type=dbcsr_type_no_symmetry)
    1451             : 
    1452             :       ! TMP=metric*ket
    1453             :       CALL dbcsr_multiply("N", "N", 1.0_dp, &
    1454             :                           metric, ket, 0.0_dp, tmp, &
    1455         378 :                           filter_eps=eps_filter)
    1456             : 
    1457             :       ! OVERLAP=tr(bra)*TMP
    1458             :       CALL dbcsr_multiply("T", "N", 1.0_dp, &
    1459             :                           bra, tmp, 0.0_dp, overlap, &
    1460             :                           retain_sparsity=local_retain_sparsity, &
    1461         378 :                           filter_eps=eps_filter)
    1462             : 
    1463         378 :       CALL dbcsr_release(tmp)
    1464             : 
    1465             :       !! If smearing ALMO is requested, apply correction of the occupation-rescaling trick
    1466             :       !! (i.e. converting rescaled orbitals into selfish orbitals)
    1467             :       !! (i.e. the diagonal blocks of the rescaled overlap must remain unscaled)
    1468             :       !! Since we have here orthonormal MOs within a fragment, diagonal blocks are identity matrices
    1469             :       !! Therefore, one only need to restore the diagonal to 1
    1470             :       !! RS-WARNING: Assume orthonormal MOs within a fragment
    1471         378 :       IF (smearing) THEN
    1472           4 :          CALL dbcsr_get_info(overlap, nfullrows_total=dim0)
    1473          12 :          ALLOCATE (diag_correction(dim0))
    1474         132 :          diag_correction = 1.0_dp
    1475           4 :          CALL dbcsr_set_diag(overlap, diag_correction)
    1476           8 :          DEALLOCATE (diag_correction)
    1477             :       END IF
    1478             : 
    1479         378 :       CALL timestop(handle)
    1480             : 
    1481         756 :    END SUBROUTINE get_overlap
    1482             : 
    1483             : ! **************************************************************************************************
    1484             : !> \brief orthogonalize MOs
    1485             : !> \param ket ...
    1486             : !> \param overlap ...
    1487             : !> \param metric ...
    1488             : !> \param retain_locality ...
    1489             : !> \param only_normalize ...
    1490             : !> \param nocc_of_domain ...
    1491             : !> \param eps_filter ...
    1492             : !> \param order_lanczos ...
    1493             : !> \param eps_lanczos ...
    1494             : !> \param max_iter_lanczos ...
    1495             : !> \param overlap_sqrti ...
    1496             : !> \param smear ...
    1497             : !> \par History
    1498             : !>       2012.03 created [Rustam Z Khaliullin]
    1499             : !>       2018.09 smearing support [Ruben Staub]
    1500             : !> \author Rustam Z Khaliullin
    1501             : ! **************************************************************************************************
    1502         378 :    SUBROUTINE orthogonalize_mos(ket, overlap, metric, retain_locality, only_normalize, &
    1503         378 :                                 nocc_of_domain, eps_filter, order_lanczos, eps_lanczos, &
    1504             :                                 max_iter_lanczos, overlap_sqrti, smear)
    1505             : 
    1506             :       TYPE(dbcsr_type), INTENT(INOUT)                    :: ket, overlap
    1507             :       TYPE(dbcsr_type), INTENT(IN)                       :: metric
    1508             :       LOGICAL, INTENT(IN)                                :: retain_locality, only_normalize
    1509             :       INTEGER, DIMENSION(:), INTENT(IN)                  :: nocc_of_domain
    1510             :       REAL(KIND=dp)                                      :: eps_filter
    1511             :       INTEGER, INTENT(IN)                                :: order_lanczos
    1512             :       REAL(KIND=dp), INTENT(IN)                          :: eps_lanczos
    1513             :       INTEGER, INTENT(IN)                                :: max_iter_lanczos
    1514             :       TYPE(dbcsr_type), INTENT(INOUT), OPTIONAL          :: overlap_sqrti
    1515             :       LOGICAL, INTENT(IN), OPTIONAL                      :: smear
    1516             : 
    1517             :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'orthogonalize_mos'
    1518             : 
    1519             :       INTEGER                                            :: dim0, handle
    1520             :       LOGICAL                                            :: smearing
    1521         378 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: diagonal
    1522             :       TYPE(dbcsr_type)                                   :: matrix_sigma_blk_sqrt, &
    1523             :                                                             matrix_sigma_blk_sqrt_inv, &
    1524             :                                                             matrix_t_blk_tmp
    1525             : 
    1526         378 :       CALL timeset(routineN, handle)
    1527             : 
    1528         378 :       IF (.NOT. PRESENT(smear)) THEN
    1529         284 :          smearing = .FALSE.
    1530             :       ELSE
    1531          94 :          smearing = smear
    1532             :       END IF
    1533             : 
    1534             :       ! create block-diagonal sparsity pattern for the overlap
    1535             :       ! in case retain_locality is set to true
    1536             :       ! RZK-warning this will fail if distribution blocks are smaller than domains!!!
    1537         378 :       CALL dbcsr_set(overlap, 0.0_dp)
    1538         378 :       CALL dbcsr_add_on_diag(overlap, 1.0_dp)
    1539         378 :       CALL dbcsr_filter(overlap, eps_filter)
    1540             : 
    1541             :       CALL get_overlap(ket, ket, overlap, metric, retain_locality, &
    1542         378 :                        eps_filter, smear=smearing)
    1543             : 
    1544         378 :       IF (only_normalize) THEN
    1545             : 
    1546           0 :          CALL dbcsr_get_info(overlap, nfullrows_total=dim0)
    1547           0 :          ALLOCATE (diagonal(dim0))
    1548           0 :          CALL dbcsr_get_diag(overlap, diagonal)
    1549           0 :          CALL dbcsr_set(overlap, 0.0_dp)
    1550           0 :          CALL dbcsr_set_diag(overlap, diagonal)
    1551           0 :          DEALLOCATE (diagonal)
    1552           0 :          CALL dbcsr_filter(overlap, eps_filter)
    1553             : 
    1554             :       END IF
    1555             : 
    1556             :       CALL dbcsr_create(matrix_sigma_blk_sqrt, template=overlap, &
    1557         378 :                         matrix_type=dbcsr_type_no_symmetry)
    1558             :       CALL dbcsr_create(matrix_sigma_blk_sqrt_inv, template=overlap, &
    1559         378 :                         matrix_type=dbcsr_type_no_symmetry)
    1560             : 
    1561             :       ! compute sqrt and sqrt_inv of the blocked MO overlap
    1562         378 :       CALL set_zero_electron_blocks_in_mo_mo_matrix(overlap, nocc_of_domain, 1.0_dp)
    1563             :       CALL matrix_sqrt_Newton_Schulz(matrix_sigma_blk_sqrt, matrix_sigma_blk_sqrt_inv, &
    1564             :                                      overlap, threshold=eps_filter, &
    1565             :                                      order=order_lanczos, &
    1566             :                                      eps_lanczos=eps_lanczos, &
    1567         378 :                                      max_iter_lanczos=max_iter_lanczos)
    1568         378 :       CALL set_zero_electron_blocks_in_mo_mo_matrix(overlap, nocc_of_domain, 0.0_dp)
    1569             :       !CALL set_zero_electron_blocks_in_mo_mo_matrix(matrix_sigma_blk_sqrt,nocc_of_domain,0.0_dp)
    1570         378 :       CALL set_zero_electron_blocks_in_mo_mo_matrix(matrix_sigma_blk_sqrt_inv, nocc_of_domain, 0.0_dp)
    1571             : 
    1572             :       CALL dbcsr_create(matrix_t_blk_tmp, &
    1573             :                         template=ket, &
    1574         378 :                         matrix_type=dbcsr_type_no_symmetry)
    1575             : 
    1576             :       CALL dbcsr_multiply("N", "N", 1.0_dp, &
    1577             :                           ket, &
    1578             :                           matrix_sigma_blk_sqrt_inv, &
    1579             :                           0.0_dp, matrix_t_blk_tmp, &
    1580         378 :                           filter_eps=eps_filter)
    1581             : 
    1582             :       ! update the orbitals with the orthonormalized MOs
    1583         378 :       CALL dbcsr_copy(ket, matrix_t_blk_tmp)
    1584             : 
    1585             :       ! return overlap SQRT_INV if necessary
    1586         378 :       IF (PRESENT(overlap_sqrti)) THEN
    1587             :          CALL dbcsr_copy(overlap_sqrti, &
    1588           0 :                          matrix_sigma_blk_sqrt_inv)
    1589             :       END IF
    1590             : 
    1591         378 :       CALL dbcsr_release(matrix_t_blk_tmp)
    1592         378 :       CALL dbcsr_release(matrix_sigma_blk_sqrt)
    1593         378 :       CALL dbcsr_release(matrix_sigma_blk_sqrt_inv)
    1594             : 
    1595         378 :       CALL timestop(handle)
    1596             : 
    1597         756 :    END SUBROUTINE orthogonalize_mos
    1598             : 
    1599             : ! **************************************************************************************************
    1600             : !> \brief computes the idempotent density matrix from MOs
    1601             : !>        MOs can be either orthogonal or non-orthogonal
    1602             : !> \param t ...
    1603             : !> \param p ...
    1604             : !> \param eps_filter ...
    1605             : !> \param orthog_orbs ...
    1606             : !> \param nocc_of_domain ...
    1607             : !> \param s ...
    1608             : !> \param sigma ...
    1609             : !> \param sigma_inv ...
    1610             : !> \param use_guess ...
    1611             : !> \param smear ...
    1612             : !> \param algorithm to inver sigma: 0 - Hotelling (linear), 1 - Cholesky (cubic, low prefactor)
    1613             : !> \param para_env ...
    1614             : !> \param blacs_env ...
    1615             : !> \param eps_lanczos ...
    1616             : !> \param max_iter_lanczos ...
    1617             : !> \param inverse_accelerator ...
    1618             : !> \param inv_eps_factor ...
    1619             : !> \par History
    1620             : !>       2011.07 created [Rustam Z Khaliullin]
    1621             : !>       2018.09 smearing support [Ruben Staub]
    1622             : !> \author Rustam Z Khaliullin
    1623             : ! **************************************************************************************************
    1624        1948 :    SUBROUTINE almo_scf_t_to_proj(t, p, eps_filter, orthog_orbs, nocc_of_domain, s, sigma, sigma_inv, &
    1625             :                                  use_guess, smear, algorithm, para_env, blacs_env, eps_lanczos, &
    1626             :                                  max_iter_lanczos, inverse_accelerator, inv_eps_factor)
    1627             : 
    1628             :       TYPE(dbcsr_type), INTENT(IN)                       :: t
    1629             :       TYPE(dbcsr_type), INTENT(INOUT)                    :: p
    1630             :       REAL(KIND=dp), INTENT(IN)                          :: eps_filter
    1631             :       LOGICAL, INTENT(IN)                                :: orthog_orbs
    1632             :       INTEGER, DIMENSION(:), INTENT(IN), OPTIONAL        :: nocc_of_domain
    1633             :       TYPE(dbcsr_type), INTENT(IN), OPTIONAL             :: s
    1634             :       TYPE(dbcsr_type), INTENT(INOUT), OPTIONAL          :: sigma, sigma_inv
    1635             :       LOGICAL, INTENT(IN), OPTIONAL                      :: use_guess, smear
    1636             :       INTEGER, INTENT(IN), OPTIONAL                      :: algorithm
    1637             :       TYPE(mp_para_env_type), OPTIONAL, POINTER          :: para_env
    1638             :       TYPE(cp_blacs_env_type), OPTIONAL, POINTER         :: blacs_env
    1639             :       REAL(KIND=dp), INTENT(IN), OPTIONAL                :: eps_lanczos
    1640             :       INTEGER, INTENT(IN), OPTIONAL                      :: max_iter_lanczos, inverse_accelerator
    1641             :       REAL(KIND=dp), INTENT(IN), OPTIONAL                :: inv_eps_factor
    1642             : 
    1643             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'almo_scf_t_to_proj'
    1644             : 
    1645             :       INTEGER                                            :: dim0, handle, my_accelerator, &
    1646             :                                                             my_algorithm
    1647             :       LOGICAL                                            :: smearing, use_sigma_inv_guess
    1648             :       REAL(KIND=dp)                                      :: my_inv_eps_factor
    1649        1948 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: diag_correction
    1650             :       TYPE(dbcsr_type)                                   :: t_tmp
    1651             : 
    1652        1948 :       CALL timeset(routineN, handle)
    1653             : 
    1654             :       ! make sure that S, sigma and sigma_inv are present for non-orthogonal orbitals
    1655        1948 :       IF (.NOT. orthog_orbs) THEN
    1656             :          IF ((.NOT. PRESENT(s)) .OR. (.NOT. PRESENT(sigma)) .OR. &
    1657        1948 :              (.NOT. PRESENT(sigma_inv)) .OR. (.NOT. PRESENT(nocc_of_domain))) THEN
    1658           0 :             CPABORT("Nonorthogonal orbitals need more input")
    1659             :          END IF
    1660             :       END IF
    1661             : 
    1662        1948 :       my_algorithm = 0
    1663        1948 :       IF (PRESENT(algorithm)) my_algorithm = algorithm
    1664             : 
    1665        1948 :       IF (my_algorithm == 1 .AND. (.NOT. PRESENT(para_env) .OR. .NOT. PRESENT(blacs_env))) &
    1666           0 :          CPABORT("PARA and BLACS env are necessary for cholesky algorithm")
    1667             : 
    1668        1948 :       use_sigma_inv_guess = .FALSE.
    1669        1948 :       IF (PRESENT(use_guess)) THEN
    1670        1948 :          use_sigma_inv_guess = use_guess
    1671             :       END IF
    1672             : 
    1673        1948 :       IF (.NOT. PRESENT(smear)) THEN
    1674             :          smearing = .FALSE.
    1675             :       ELSE
    1676         466 :          smearing = smear
    1677             :       END IF
    1678             : 
    1679        1948 :       my_accelerator = 1
    1680        1948 :       IF (PRESENT(inverse_accelerator)) my_accelerator = inverse_accelerator
    1681             : 
    1682        1948 :       my_inv_eps_factor = 10.0_dp
    1683        1948 :       IF (PRESENT(inv_eps_factor)) my_inv_eps_factor = inv_eps_factor
    1684             : 
    1685        1948 :       IF (orthog_orbs) THEN
    1686             : 
    1687             :          CALL dbcsr_multiply("N", "T", 1.0_dp, t, t, &
    1688           0 :                              0.0_dp, p, filter_eps=eps_filter)
    1689             : 
    1690             :       ELSE
    1691             : 
    1692        1948 :          CALL dbcsr_create(t_tmp, template=t)
    1693             : 
    1694             :          ! TMP=S.T
    1695             :          CALL dbcsr_multiply("N", "N", 1.0_dp, s, t, 0.0_dp, t_tmp, &
    1696        1948 :                              filter_eps=eps_filter)
    1697             : 
    1698             :          ! Sig=tr(T).TMP - get MO overlap
    1699             :          CALL dbcsr_multiply("T", "N", 1.0_dp, t, t_tmp, 0.0_dp, sigma, &
    1700        1948 :                              filter_eps=eps_filter)
    1701             : 
    1702             :          !! If smearing ALMO is requested, apply correction of the occupation-rescaling trick
    1703             :          !! (i.e. converting rescaled orbitals into selfish orbitals)
    1704             :          !! (i.e. the diagonal blocks of the rescaled overlap must remain unscaled)
    1705             :          !! Since we have here orthonormal MOs within a fragment, diagonal blocks are identity matrices
    1706             :          !! Therefore, one only need to restore the diagonal to 1
    1707             :          !! RS-WARNING: Assume orthonormal MOs within a fragment
    1708        1948 :          IF (smearing) THEN
    1709          20 :             CALL dbcsr_get_info(sigma, nfullrows_total=dim0)
    1710          60 :             ALLOCATE (diag_correction(dim0))
    1711         700 :             diag_correction = 1.0_dp
    1712          20 :             CALL dbcsr_set_diag(sigma, diag_correction)
    1713          40 :             DEALLOCATE (diag_correction)
    1714             :          END IF
    1715             : 
    1716             :          ! invert MO overlap
    1717        1948 :          CALL set_zero_electron_blocks_in_mo_mo_matrix(sigma, nocc_of_domain, 1.0_dp)
    1718          26 :          SELECT CASE (my_algorithm)
    1719             :          CASE (spd_inversion_ls_taylor)
    1720             : 
    1721             :             CALL invert_Taylor( &
    1722             :                matrix_inverse=sigma_inv, &
    1723             :                matrix=sigma, &
    1724             :                use_inv_as_guess=use_sigma_inv_guess, &
    1725             :                threshold=eps_filter*my_inv_eps_factor, &
    1726             :                filter_eps=eps_filter, &
    1727             :                !accelerator_order=my_accelerator, &
    1728             :                !eps_lanczos=eps_lanczos, &
    1729             :                !max_iter_lanczos=max_iter_lanczos, &
    1730          26 :                silent=.FALSE.)
    1731             : 
    1732             :          CASE (spd_inversion_ls_hotelling)
    1733             : 
    1734             :             CALL invert_Hotelling( &
    1735             :                matrix_inverse=sigma_inv, &
    1736             :                matrix=sigma, &
    1737             :                use_inv_as_guess=use_sigma_inv_guess, &
    1738             :                threshold=eps_filter*my_inv_eps_factor, &
    1739             :                filter_eps=eps_filter, &
    1740             :                accelerator_order=my_accelerator, &
    1741             :                eps_lanczos=eps_lanczos, &
    1742             :                max_iter_lanczos=max_iter_lanczos, &
    1743        1436 :                silent=.FALSE.)
    1744             : 
    1745             :          CASE (spd_inversion_dense_cholesky)
    1746             : 
    1747             :             ! invert using cholesky
    1748         486 :             CALL dbcsr_copy(sigma_inv, sigma)
    1749             :             CALL cp_dbcsr_cholesky_decompose(sigma_inv, &
    1750             :                                              para_env=para_env, &
    1751         486 :                                              blacs_env=blacs_env)
    1752             :             CALL cp_dbcsr_cholesky_invert(sigma_inv, &
    1753             :                                           para_env=para_env, &
    1754             :                                           blacs_env=blacs_env, &
    1755         486 :                                           uplo_to_full=.TRUE.)
    1756         486 :             CALL dbcsr_filter(sigma_inv, eps_filter)
    1757             :          CASE DEFAULT
    1758        1948 :             CPABORT("Illegal MO overalp inversion algorithm")
    1759             :          END SELECT
    1760        1948 :          CALL set_zero_electron_blocks_in_mo_mo_matrix(sigma, nocc_of_domain, 0.0_dp)
    1761        1948 :          CALL set_zero_electron_blocks_in_mo_mo_matrix(sigma_inv, nocc_of_domain, 0.0_dp)
    1762             : 
    1763             :          ! TMP=T.SigInv
    1764             :          CALL dbcsr_multiply("N", "N", 1.0_dp, t, sigma_inv, 0.0_dp, t_tmp, &
    1765        1948 :                              filter_eps=eps_filter)
    1766             : 
    1767             :          ! P=TMP.tr(T_blk)
    1768             :          CALL dbcsr_multiply("N", "T", 1.0_dp, t_tmp, t, 0.0_dp, p, &
    1769        1948 :                              filter_eps=eps_filter)
    1770             : 
    1771        1948 :          CALL dbcsr_release(t_tmp)
    1772             : 
    1773             :       END IF
    1774             : 
    1775        1948 :       CALL timestop(handle)
    1776             : 
    1777        3896 :    END SUBROUTINE almo_scf_t_to_proj
    1778             : 
    1779             : ! **************************************************************************************************
    1780             : !> \brief self-explanatory
    1781             : !> \param matrix ...
    1782             : !> \param nocc_of_domain ...
    1783             : !> \param value ...
    1784             : !> \param
    1785             : !> \par History
    1786             : !>       2016.12 created [Rustam Z Khaliullin]
    1787             : !> \author Rustam Z Khaliullin
    1788             : ! **************************************************************************************************
    1789        6978 :    SUBROUTINE set_zero_electron_blocks_in_mo_mo_matrix(matrix, nocc_of_domain, value)
    1790             : 
    1791             :       TYPE(dbcsr_type), INTENT(INOUT)                    :: matrix
    1792             :       INTEGER, DIMENSION(:), INTENT(IN)                  :: nocc_of_domain
    1793             :       REAL(KIND=dp), INTENT(IN)                          :: value
    1794             : 
    1795             :       INTEGER                                            :: hold, iblock_col, iblock_row, mynode, &
    1796             :                                                             nblkrows_tot, row
    1797             :       LOGICAL                                            :: found, tr
    1798        6978 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: p_new_block
    1799             :       TYPE(dbcsr_distribution_type)                      :: dist
    1800             : 
    1801        6978 :       CALL dbcsr_get_info(matrix, distribution=dist)
    1802        6978 :       CALL dbcsr_distribution_get(dist, mynode=mynode)
    1803             :       !mynode = dbcsr_mp_mynode(dbcsr_distribution_mp(dbcsr_distribution(matrix)))
    1804        6978 :       CALL dbcsr_work_create(matrix, work_mutable=.TRUE.)
    1805             : 
    1806        6978 :       nblkrows_tot = dbcsr_nblkrows_total(matrix)
    1807             : 
    1808       53406 :       DO row = 1, nblkrows_tot
    1809       53406 :          IF (nocc_of_domain(row) == 0) THEN
    1810        7632 :             tr = .FALSE.
    1811        7632 :             iblock_row = row
    1812        7632 :             iblock_col = row
    1813        7632 :             CALL dbcsr_get_stored_coordinates(matrix, iblock_row, iblock_col, hold)
    1814        7632 :             IF (hold .EQ. mynode) THEN
    1815        3816 :                NULLIFY (p_new_block)
    1816        3816 :                CALL dbcsr_get_block_p(matrix, iblock_row, iblock_col, p_new_block, found)
    1817        3816 :                IF (found) THEN
    1818        2792 :                   p_new_block(1, 1) = value
    1819             :                ELSE
    1820        1024 :                   CALL dbcsr_reserve_block2d(matrix, iblock_row, iblock_col, p_new_block)
    1821        1024 :                   CPASSERT(ASSOCIATED(p_new_block))
    1822        1024 :                   p_new_block(1, 1) = value
    1823             :                END IF
    1824             :             END IF ! mynode
    1825             :          END IF !zero-electron block
    1826             :       END DO
    1827             : 
    1828        6978 :       CALL dbcsr_finalize(matrix)
    1829             : 
    1830        6978 :    END SUBROUTINE set_zero_electron_blocks_in_mo_mo_matrix
    1831             : 
    1832             : ! **************************************************************************************************
    1833             : !> \brief applies projector to the orbitals
    1834             : !>        |psi_out> = P |psi_in>   OR   |psi_out> = (1-P) |psi_in>,
    1835             : !>        where P = |psi_proj> (<psi_proj|psi_roj>)^{-1} <psi_proj|
    1836             : !> \param psi_in ...
    1837             : !> \param psi_out ...
    1838             : !> \param psi_projector ...
    1839             : !> \param metric ...
    1840             : !> \param project_out ...
    1841             : !> \param psi_projector_orthogonal ...
    1842             : !> \param proj_in_template ...
    1843             : !> \param eps_filter ...
    1844             : !> \param sig_inv_projector ...
    1845             : !> \param sig_inv_template ...
    1846             : !> \par History
    1847             : !>       2011.10 created [Rustam Z Khaliullin]
    1848             : !> \author Rustam Z Khaliullin
    1849             : ! **************************************************************************************************
    1850           0 :    SUBROUTINE apply_projector(psi_in, psi_out, psi_projector, metric, project_out, &
    1851             :                               psi_projector_orthogonal, proj_in_template, eps_filter, sig_inv_projector, &
    1852             :                               sig_inv_template)
    1853             : 
    1854             :       TYPE(dbcsr_type), INTENT(IN)                       :: psi_in
    1855             :       TYPE(dbcsr_type), INTENT(INOUT)                    :: psi_out
    1856             :       TYPE(dbcsr_type), INTENT(IN)                       :: psi_projector, metric
    1857             :       LOGICAL, INTENT(IN)                                :: project_out, psi_projector_orthogonal
    1858             :       TYPE(dbcsr_type), INTENT(IN)                       :: proj_in_template
    1859             :       REAL(KIND=dp), INTENT(IN)                          :: eps_filter
    1860             :       TYPE(dbcsr_type), INTENT(IN), OPTIONAL             :: sig_inv_projector, sig_inv_template
    1861             : 
    1862             :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'apply_projector'
    1863             : 
    1864             :       INTEGER                                            :: handle
    1865             :       TYPE(dbcsr_type)                                   :: tmp_no, tmp_ov, tmp_ov2, tmp_sig, &
    1866             :                                                             tmp_sig_inv
    1867             : 
    1868           0 :       CALL timeset(routineN, handle)
    1869             : 
    1870             :       ! =S*PSI_proj
    1871           0 :       CALL dbcsr_create(tmp_no, template=psi_projector)
    1872             :       CALL dbcsr_multiply("N", "N", 1.0_dp, &
    1873             :                           metric, psi_projector, &
    1874             :                           0.0_dp, tmp_no, &
    1875           0 :                           filter_eps=eps_filter)
    1876             : 
    1877             :       ! =tr(S.PSI_proj)*PSI_in
    1878           0 :       CALL dbcsr_create(tmp_ov, template=proj_in_template)
    1879             :       CALL dbcsr_multiply("T", "N", 1.0_dp, &
    1880             :                           tmp_no, psi_in, &
    1881             :                           0.0_dp, tmp_ov, &
    1882           0 :                           filter_eps=eps_filter)
    1883             : 
    1884           0 :       IF (.NOT. psi_projector_orthogonal) THEN
    1885             :          ! =SigInv_proj*Sigma_OV
    1886             :          CALL dbcsr_create(tmp_ov2, &
    1887           0 :                            template=proj_in_template)
    1888           0 :          IF (PRESENT(sig_inv_projector)) THEN
    1889             :             CALL dbcsr_create(tmp_sig_inv, &
    1890           0 :                               template=sig_inv_projector)
    1891           0 :             CALL dbcsr_copy(tmp_sig_inv, sig_inv_projector)
    1892             :          ELSE
    1893           0 :             IF (.NOT. PRESENT(sig_inv_template)) THEN
    1894           0 :                CPABORT("PROGRAMMING ERROR: provide either template or sig_inv")
    1895             :             END IF
    1896             :             ! compute inverse overlap of the projector orbitals
    1897             :             CALL dbcsr_create(tmp_sig, &
    1898             :                               template=sig_inv_template, &
    1899           0 :                               matrix_type=dbcsr_type_no_symmetry)
    1900             :             CALL dbcsr_multiply("T", "N", 1.0_dp, &
    1901             :                                 psi_projector, tmp_no, 0.0_dp, tmp_sig, &
    1902           0 :                                 filter_eps=eps_filter)
    1903             :             CALL dbcsr_create(tmp_sig_inv, &
    1904             :                               template=sig_inv_template, &
    1905           0 :                               matrix_type=dbcsr_type_no_symmetry)
    1906             :             CALL invert_Hotelling(tmp_sig_inv, tmp_sig, &
    1907           0 :                                   threshold=eps_filter)
    1908           0 :             CALL dbcsr_release(tmp_sig)
    1909             :          END IF
    1910             :          CALL dbcsr_multiply("N", "N", 1.0_dp, &
    1911             :                              tmp_sig_inv, tmp_ov, 0.0_dp, tmp_ov2, &
    1912           0 :                              filter_eps=eps_filter)
    1913           0 :          CALL dbcsr_release(tmp_sig_inv)
    1914           0 :          CALL dbcsr_copy(tmp_ov, tmp_ov2)
    1915           0 :          CALL dbcsr_release(tmp_ov2)
    1916             :       END IF
    1917           0 :       CALL dbcsr_release(tmp_no)
    1918             : 
    1919             :       ! =PSI_proj*TMP_OV
    1920             :       CALL dbcsr_multiply("N", "N", 1.0_dp, &
    1921             :                           psi_projector, tmp_ov, 0.0_dp, psi_out, &
    1922           0 :                           filter_eps=eps_filter)
    1923           0 :       CALL dbcsr_release(tmp_ov)
    1924             : 
    1925             :       ! V_out=V_in-V_out
    1926           0 :       IF (project_out) THEN
    1927           0 :          CALL dbcsr_add(psi_out, psi_in, -1.0_dp, +1.0_dp)
    1928             :       END IF
    1929             : 
    1930           0 :       CALL timestop(handle)
    1931             : 
    1932           0 :    END SUBROUTINE apply_projector
    1933             : 
    1934             : !! **************************************************************************************************
    1935             : !!> \brief projects the occupied space out from the provided orbitals
    1936             : !!> \par History
    1937             : !!>       2011.07 created [Rustam Z Khaliullin]
    1938             : !!> \author Rustam Z Khaliullin
    1939             : !! **************************************************************************************************
    1940             : !  SUBROUTINE almo_scf_p_out_from_v(v_in,v_out,ov_template,ispin,almo_scf_env)
    1941             : !
    1942             : !    TYPE(dbcsr_type), INTENT(IN)                :: v_in, ov_template
    1943             : !    TYPE(dbcsr_type), INTENT(INOUT)             :: v_out
    1944             : !    INTEGER, INTENT(IN)                            :: ispin
    1945             : !    TYPE(almo_scf_env_type), INTENT(INOUT)         :: almo_scf_env
    1946             : !
    1947             : !    CHARACTER(LEN=*), PARAMETER :: &
    1948             : !      routineN = 'almo_scf_p_out_from_v', &
    1949             : !      routineP = moduleN//':'//routineN
    1950             : !
    1951             : !    TYPE(dbcsr_type)                      :: tmp_on, tmp_ov, tmp_ov2
    1952             : !    INTEGER                                  :: handle
    1953             : !    LOGICAL                                  :: failure
    1954             : !
    1955             : !    CALL timeset(routineN,handle)
    1956             : !
    1957             : !    ! =tr(T_blk)*S
    1958             : !    CALL dbcsr_init(tmp_on)
    1959             : !    CALL dbcsr_create(tmp_on,&
    1960             : !            template=almo_scf_env%matrix_t_tr(ispin))
    1961             : !    CALL dbcsr_multiply("T","N",1.0_dp,&
    1962             : !            almo_scf_env%matrix_t_blk(ispin),&
    1963             : !            almo_scf_env%matrix_s(1),&
    1964             : !            0.0_dp,tmp_on,&
    1965             : !            filter_eps=almo_scf_env%eps_filter)
    1966             : !
    1967             : !    ! =tr(T_blk).S*V_in
    1968             : !    CALL dbcsr_init(tmp_ov)
    1969             : !    CALL dbcsr_create(tmp_ov,template=ov_template)
    1970             : !    CALL dbcsr_multiply("N","N",1.0_dp,&
    1971             : !            tmp_on,v_in,0.0_dp,tmp_ov,&
    1972             : !            filter_eps=almo_scf_env%eps_filter)
    1973             : !    CALL dbcsr_release(tmp_on)
    1974             : !
    1975             : !    ! =SigmaInv*Sigma_OV
    1976             : !    CALL dbcsr_init(tmp_ov2)
    1977             : !    CALL dbcsr_create(tmp_ov2,template=ov_template)
    1978             : !    CALL dbcsr_multiply("N","N",1.0_dp,&
    1979             : !            almo_scf_env%matrix_sigma_inv(ispin),&
    1980             : !            tmp_ov,0.0_dp,tmp_ov2,&
    1981             : !            filter_eps=almo_scf_env%eps_filter)
    1982             : !    CALL dbcsr_release(tmp_ov)
    1983             : !
    1984             : !    ! =T_blk*SigmaInv.Sigma_OV
    1985             : !    CALL dbcsr_multiply("N","N",1.0_dp,&
    1986             : !            almo_scf_env%matrix_t_blk(ispin),&
    1987             : !            tmp_ov2,0.0_dp,v_out,&
    1988             : !            filter_eps=almo_scf_env%eps_filter)
    1989             : !    CALL dbcsr_release(tmp_ov2)
    1990             : !
    1991             : !    ! V_out=V_in-V_out=
    1992             : !    CALL dbcsr_add(v_out,v_in,-1.0_dp,+1.0_dp)
    1993             : !
    1994             : !    CALL timestop(handle)
    1995             : !
    1996             : !  END SUBROUTINE almo_scf_p_out_from_v
    1997             : 
    1998             : ! **************************************************************************************************
    1999             : !> \brief computes a unitary matrix from an arbitrary "generator" matrix
    2000             : !>        U = ( 1 - X + tr(X) ) ( 1 + X - tr(X) )^(-1)
    2001             : !> \param X ...
    2002             : !> \param U ...
    2003             : !> \param eps_filter ...
    2004             : !> \par History
    2005             : !>       2011.08 created [Rustam Z Khaliullin]
    2006             : !> \author Rustam Z Khaliullin
    2007             : ! **************************************************************************************************
    2008           0 :    SUBROUTINE generator_to_unitary(X, U, eps_filter)
    2009             : 
    2010             :       TYPE(dbcsr_type), INTENT(IN)                       :: X
    2011             :       TYPE(dbcsr_type), INTENT(INOUT)                    :: U
    2012             :       REAL(KIND=dp), INTENT(IN)                          :: eps_filter
    2013             : 
    2014             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'generator_to_unitary'
    2015             : 
    2016             :       INTEGER                                            :: handle, unit_nr
    2017             :       LOGICAL                                            :: safe_mode
    2018             :       REAL(KIND=dp)                                      :: frob_matrix, frob_matrix_base
    2019             :       TYPE(cp_logger_type), POINTER                      :: logger
    2020             :       TYPE(dbcsr_type)                                   :: delta, t1, t2, tmp1
    2021             : 
    2022           0 :       CALL timeset(routineN, handle)
    2023             : 
    2024           0 :       safe_mode = .TRUE.
    2025             : 
    2026             :       ! get a useful output_unit
    2027           0 :       logger => cp_get_default_logger()
    2028           0 :       IF (logger%para_env%is_source()) THEN
    2029           0 :          unit_nr = cp_logger_get_default_unit_nr(logger, local=.TRUE.)
    2030             :       ELSE
    2031             :          unit_nr = -1
    2032             :       END IF
    2033             : 
    2034             :       CALL dbcsr_create(t1, template=X, &
    2035           0 :                         matrix_type=dbcsr_type_no_symmetry)
    2036             :       CALL dbcsr_create(t2, template=X, &
    2037           0 :                         matrix_type=dbcsr_type_no_symmetry)
    2038             : 
    2039             :       ! create antisymmetric Delta = -X + tr(X)
    2040             :       CALL dbcsr_create(delta, template=X, &
    2041           0 :                         matrix_type=dbcsr_type_no_symmetry)
    2042           0 :       CALL dbcsr_transposed(delta, X)
    2043             : ! check that transposed is added correctly
    2044           0 :       CALL dbcsr_add(delta, X, 1.0_dp, -1.0_dp)
    2045             : 
    2046             :       ! compute (1 - Delta)^(-1)
    2047           0 :       CALL dbcsr_add_on_diag(t1, 1.0_dp)
    2048           0 :       CALL dbcsr_add(t1, delta, 1.0_dp, -1.0_dp)
    2049           0 :       CALL invert_Hotelling(t2, t1, threshold=eps_filter)
    2050             : 
    2051             :       IF (safe_mode) THEN
    2052             : 
    2053             :          CALL dbcsr_create(tmp1, template=X, &
    2054           0 :                            matrix_type=dbcsr_type_no_symmetry)
    2055             :          CALL dbcsr_multiply("N", "N", 1.0_dp, t2, t1, 0.0_dp, tmp1, &
    2056           0 :                              filter_eps=eps_filter)
    2057           0 :          frob_matrix_base = dbcsr_frobenius_norm(tmp1)
    2058           0 :          CALL dbcsr_add_on_diag(tmp1, -1.0_dp)
    2059           0 :          frob_matrix = dbcsr_frobenius_norm(tmp1)
    2060           0 :          IF (unit_nr > 0) WRITE (unit_nr, *) "Error for (inv(A)*A-I)", frob_matrix/frob_matrix_base
    2061           0 :          CALL dbcsr_release(tmp1)
    2062             :       END IF
    2063             : 
    2064             :       CALL dbcsr_multiply("N", "N", 1.0_dp, delta, t2, 0.0_dp, U, &
    2065           0 :                           filter_eps=eps_filter)
    2066           0 :       CALL dbcsr_add(U, t2, 1.0_dp, 1.0_dp)
    2067             : 
    2068             :       IF (safe_mode) THEN
    2069             : 
    2070             :          CALL dbcsr_create(tmp1, template=X, &
    2071           0 :                            matrix_type=dbcsr_type_no_symmetry)
    2072             :          CALL dbcsr_multiply("T", "N", 1.0_dp, U, U, 0.0_dp, tmp1, &
    2073           0 :                              filter_eps=eps_filter)
    2074           0 :          frob_matrix_base = dbcsr_frobenius_norm(tmp1)
    2075           0 :          CALL dbcsr_add_on_diag(tmp1, -1.0_dp)
    2076           0 :          frob_matrix = dbcsr_frobenius_norm(tmp1)
    2077           0 :          IF (unit_nr > 0) WRITE (unit_nr, *) "Error for (trn(U)*U-I)", frob_matrix/frob_matrix_base
    2078           0 :          CALL dbcsr_release(tmp1)
    2079             :       END IF
    2080             : 
    2081           0 :       CALL timestop(handle)
    2082             : 
    2083           0 :    END SUBROUTINE generator_to_unitary
    2084             : 
    2085             : ! **************************************************************************************************
    2086             : !> \brief Parallel code for domain specific operations (my_action)
    2087             : !>         0. out = op1 * in
    2088             : !>         1. out = in - op2 * op1 * in
    2089             : !> \param matrix_in ...
    2090             : !> \param matrix_out ...
    2091             : !> \param operator1 ...
    2092             : !> \param operator2 ...
    2093             : !> \param dpattern ...
    2094             : !> \param map ...
    2095             : !> \param node_of_domain ...
    2096             : !> \param my_action ...
    2097             : !> \param filter_eps ...
    2098             : !> \param matrix_trimmer ...
    2099             : !> \param use_trimmer ...
    2100             : !> \par History
    2101             : !>       2013.01 created [Rustam Z. Khaliullin]
    2102             : !> \author Rustam Z. Khaliullin
    2103             : ! **************************************************************************************************
    2104        2394 :    SUBROUTINE apply_domain_operators(matrix_in, matrix_out, operator1, operator2, &
    2105        2394 :                                      dpattern, map, node_of_domain, my_action, filter_eps, matrix_trimmer, use_trimmer)
    2106             : 
    2107             :       TYPE(dbcsr_type), INTENT(IN)                       :: matrix_in
    2108             :       TYPE(dbcsr_type), INTENT(INOUT)                    :: matrix_out
    2109             :       TYPE(domain_submatrix_type), DIMENSION(:), &
    2110             :          INTENT(IN)                                      :: operator1
    2111             :       TYPE(domain_submatrix_type), DIMENSION(:), &
    2112             :          INTENT(IN), OPTIONAL                            :: operator2
    2113             :       TYPE(dbcsr_type), INTENT(IN)                       :: dpattern
    2114             :       TYPE(domain_map_type), INTENT(IN)                  :: map
    2115             :       INTEGER, DIMENSION(:), INTENT(IN)                  :: node_of_domain
    2116             :       INTEGER, INTENT(IN)                                :: my_action
    2117             :       REAL(KIND=dp)                                      :: filter_eps
    2118             :       TYPE(dbcsr_type), INTENT(IN), OPTIONAL             :: matrix_trimmer
    2119             :       LOGICAL, INTENT(IN), OPTIONAL                      :: use_trimmer
    2120             : 
    2121             :       CHARACTER(len=*), PARAMETER :: routineN = 'apply_domain_operators'
    2122             : 
    2123             :       INTEGER                                            :: handle, ndomains
    2124             :       LOGICAL                                            :: matrix_trimmer_required, my_use_trimmer, &
    2125             :                                                             operator2_required
    2126             :       TYPE(domain_submatrix_type), ALLOCATABLE, &
    2127        2394 :          DIMENSION(:)                                    :: subm_in, subm_out, subm_temp
    2128             : 
    2129        2394 :       CALL timeset(routineN, handle)
    2130             : 
    2131        2394 :       my_use_trimmer = .FALSE.
    2132        2394 :       IF (PRESENT(use_trimmer)) THEN
    2133         612 :          my_use_trimmer = use_trimmer
    2134             :       END IF
    2135             : 
    2136        2394 :       operator2_required = .FALSE.
    2137        2394 :       matrix_trimmer_required = .FALSE.
    2138             : 
    2139        2394 :       IF (my_action .EQ. 1) operator2_required = .TRUE.
    2140             : 
    2141        2394 :       IF (my_use_trimmer) THEN
    2142           0 :          matrix_trimmer_required = .TRUE.
    2143           0 :          CPABORT("TRIMMED PROJECTOR DISABLED!")
    2144             :       END IF
    2145             : 
    2146        2394 :       IF (.NOT. PRESENT(operator2) .AND. operator2_required) THEN
    2147           0 :          CPABORT("SECOND OPERATOR IS REQUIRED")
    2148             :       END IF
    2149        2394 :       IF (.NOT. PRESENT(matrix_trimmer) .AND. matrix_trimmer_required) THEN
    2150           0 :          CPABORT("TRIMMER MATRIX IS REQUIRED")
    2151             :       END IF
    2152             : 
    2153        2394 :       ndomains = dbcsr_nblkcols_total(dpattern)
    2154             : 
    2155       22832 :       ALLOCATE (subm_in(ndomains))
    2156       20438 :       ALLOCATE (subm_temp(ndomains))
    2157       20438 :       ALLOCATE (subm_out(ndomains))
    2158             :       !!!TRIM ALLOCATE(subm_trimmer(ndomains))
    2159        2394 :       CALL init_submatrices(subm_in)
    2160        2394 :       CALL init_submatrices(subm_temp)
    2161        2394 :       CALL init_submatrices(subm_out)
    2162             : 
    2163             :       CALL construct_submatrices(matrix_in, subm_in, &
    2164        2394 :                                  dpattern, map, node_of_domain, select_row)
    2165             : 
    2166             :       !!!TRIM IF (matrix_trimmer_required) THEN
    2167             :       !!!TRIM    CALL construct_submatrices(matrix_trimmer,subm_trimmer,&
    2168             :       !!!TRIM            dpattern,map,node_of_domain,select_row)
    2169             :       !!!TRIM ENDIF
    2170             : 
    2171        2394 :       IF (my_action .EQ. 0) THEN
    2172             :          ! for example, apply preconditioner
    2173             :          CALL multiply_submatrices('N', 'N', 1.0_dp, operator1, &
    2174        1552 :                                    subm_in, 0.0_dp, subm_out)
    2175         842 :       ELSE IF (my_action .EQ. 1) THEN
    2176             :          ! use for projectors
    2177         842 :          CALL copy_submatrices(subm_in, subm_out, .TRUE.)
    2178             :          CALL multiply_submatrices('N', 'N', 1.0_dp, operator1, &
    2179         842 :                                    subm_in, 0.0_dp, subm_temp)
    2180             :          CALL multiply_submatrices('N', 'N', -1.0_dp, operator2, &
    2181         842 :                                    subm_temp, 1.0_dp, subm_out)
    2182             :       ELSE
    2183           0 :          CPABORT("ILLEGAL ACTION")
    2184             :       END IF
    2185             : 
    2186        2394 :       CALL construct_dbcsr_from_submatrices(matrix_out, subm_out, dpattern)
    2187        2394 :       CALL dbcsr_filter(matrix_out, filter_eps)
    2188             : 
    2189        2394 :       CALL release_submatrices(subm_out)
    2190        2394 :       CALL release_submatrices(subm_temp)
    2191        2394 :       CALL release_submatrices(subm_in)
    2192             : 
    2193       18044 :       DEALLOCATE (subm_out)
    2194       18044 :       DEALLOCATE (subm_temp)
    2195       18044 :       DEALLOCATE (subm_in)
    2196             : 
    2197        2394 :       CALL timestop(handle)
    2198             : 
    2199        2394 :    END SUBROUTINE apply_domain_operators
    2200             : 
    2201             : ! **************************************************************************************************
    2202             : !> \brief Constructs preconditioners for each domain
    2203             : !>        -1. projected preconditioner
    2204             : !>         0. simple preconditioner
    2205             : !> \param matrix_main ...
    2206             : !> \param subm_s_inv ...
    2207             : !> \param subm_s_inv_half ...
    2208             : !> \param subm_s_half ...
    2209             : !> \param subm_r_down ...
    2210             : !> \param matrix_trimmer ...
    2211             : !> \param dpattern ...
    2212             : !> \param map ...
    2213             : !> \param node_of_domain ...
    2214             : !> \param preconditioner ...
    2215             : !> \param bad_modes_projector_down ...
    2216             : !> \param use_trimmer ...
    2217             : !> \param eps_zero_eigenvalues ...
    2218             : !> \param my_action ...
    2219             : !> \param skip_inversion ...
    2220             : !> \par History
    2221             : !>       2013.01 created [Rustam Z. Khaliullin]
    2222             : !> \author Rustam Z. Khaliullin
    2223             : ! **************************************************************************************************
    2224         550 :    SUBROUTINE construct_domain_preconditioner(matrix_main, subm_s_inv, &
    2225         550 :                                               subm_s_inv_half, subm_s_half, &
    2226         550 :                                               subm_r_down, matrix_trimmer, &
    2227         550 :                                               dpattern, map, node_of_domain, &
    2228         550 :                                               preconditioner, &
    2229         550 :                                               bad_modes_projector_down, &
    2230             :                                               use_trimmer, &
    2231             :                                               eps_zero_eigenvalues, &
    2232             :                                               my_action, skip_inversion)
    2233             : 
    2234             :       TYPE(dbcsr_type), INTENT(INOUT)                    :: matrix_main
    2235             :       TYPE(domain_submatrix_type), DIMENSION(:), &
    2236             :          INTENT(IN), OPTIONAL                            :: subm_s_inv, subm_s_inv_half, &
    2237             :                                                             subm_s_half, subm_r_down
    2238             :       TYPE(dbcsr_type), INTENT(IN), OPTIONAL             :: matrix_trimmer
    2239             :       TYPE(dbcsr_type), INTENT(IN)                       :: dpattern
    2240             :       TYPE(domain_map_type), INTENT(IN)                  :: map
    2241             :       INTEGER, DIMENSION(:), INTENT(IN)                  :: node_of_domain
    2242             :       TYPE(domain_submatrix_type), DIMENSION(:), &
    2243             :          INTENT(INOUT)                                   :: preconditioner
    2244             :       TYPE(domain_submatrix_type), DIMENSION(:), &
    2245             :          INTENT(INOUT), OPTIONAL                         :: bad_modes_projector_down
    2246             :       LOGICAL, INTENT(IN), OPTIONAL                      :: use_trimmer
    2247             :       REAL(KIND=dp), INTENT(IN), OPTIONAL                :: eps_zero_eigenvalues
    2248             :       INTEGER, INTENT(IN)                                :: my_action
    2249             :       LOGICAL, INTENT(IN), OPTIONAL                      :: skip_inversion
    2250             : 
    2251             :       CHARACTER(len=*), PARAMETER :: routineN = 'construct_domain_preconditioner'
    2252             : 
    2253             :       INTEGER                                            :: handle, idomain, index1_end, &
    2254             :                                                             index1_start, n_domain_mos, naos, &
    2255             :                                                             nblkrows_tot, ndomains, neighbor, row
    2256         550 :       INTEGER, DIMENSION(:), POINTER                     :: nmos
    2257             :       LOGICAL :: eps_zero_eigenvalues_required, matrix_r_required, matrix_s_half_required, &
    2258             :          matrix_s_inv_half_required, matrix_s_inv_required, matrix_trimmer_required, &
    2259             :          my_skip_inversion, my_use_trimmer
    2260         550 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: Minv, proj_array
    2261             :       TYPE(domain_submatrix_type), ALLOCATABLE, &
    2262         550 :          DIMENSION(:)                                    :: subm_main, subm_tmp, subm_tmp2
    2263             : 
    2264         550 :       CALL timeset(routineN, handle)
    2265             : 
    2266         550 :       my_use_trimmer = .FALSE.
    2267         550 :       IF (PRESENT(use_trimmer)) THEN
    2268         550 :          my_use_trimmer = use_trimmer
    2269             :       END IF
    2270             : 
    2271         550 :       my_skip_inversion = .FALSE.
    2272         550 :       IF (PRESENT(skip_inversion)) THEN
    2273         550 :          my_skip_inversion = skip_inversion
    2274             :       END IF
    2275             : 
    2276         550 :       matrix_s_inv_half_required = .FALSE.
    2277         550 :       matrix_s_half_required = .FALSE.
    2278         550 :       eps_zero_eigenvalues_required = .FALSE.
    2279         550 :       matrix_s_inv_required = .FALSE.
    2280         550 :       matrix_trimmer_required = .FALSE.
    2281         550 :       matrix_r_required = .FALSE.
    2282             : 
    2283         550 :       IF (my_action .EQ. -1) matrix_s_inv_required = .TRUE.
    2284             :       IF (my_action .EQ. -1) matrix_r_required = .TRUE.
    2285         550 :       IF (my_use_trimmer) THEN
    2286           0 :          matrix_trimmer_required = .TRUE.
    2287           0 :          CPABORT("TRIMMED PRECONDITIONER DISABLED!")
    2288             :       END IF
    2289             :       ! tie the following optional arguments together to prevent bad calls
    2290         550 :       IF (PRESENT(bad_modes_projector_down)) THEN
    2291          18 :          matrix_s_inv_half_required = .TRUE.
    2292          18 :          matrix_s_half_required = .TRUE.
    2293          18 :          eps_zero_eigenvalues_required = .TRUE.
    2294             :       END IF
    2295             : 
    2296             :       ! check if all required optional arguments are provided
    2297         550 :       IF (.NOT. PRESENT(subm_s_inv_half) .AND. matrix_s_inv_half_required) THEN
    2298           0 :          CPABORT("S_inv_half SUBMATRICES ARE REQUIRED")
    2299             :       END IF
    2300         550 :       IF (.NOT. PRESENT(subm_s_half) .AND. matrix_s_half_required) THEN
    2301           0 :          CPABORT("S_half SUBMATRICES ARE REQUIRED")
    2302             :       END IF
    2303         550 :       IF (.NOT. PRESENT(eps_zero_eigenvalues) .AND. eps_zero_eigenvalues_required) THEN
    2304           0 :          CPABORT("EPS_ZERO_EIGENVALUES IS REQUIRED")
    2305             :       END IF
    2306         550 :       IF (.NOT. PRESENT(subm_s_inv) .AND. matrix_s_inv_required) THEN
    2307           0 :          CPABORT("S_inv SUBMATRICES ARE REQUIRED")
    2308             :       END IF
    2309         550 :       IF (.NOT. PRESENT(subm_r_down) .AND. matrix_r_required) THEN
    2310           0 :          CPABORT("R SUBMATRICES ARE REQUIRED")
    2311             :       END IF
    2312         550 :       IF (.NOT. PRESENT(matrix_trimmer) .AND. matrix_trimmer_required) THEN
    2313           0 :          CPABORT("TRIMMER MATRIX IS REQUIRED")
    2314             :       END IF
    2315             : 
    2316             :       CALL dbcsr_get_info(dpattern, &
    2317             :                           nblkcols_total=ndomains, &
    2318             :                           nblkrows_total=nblkrows_tot, &
    2319         550 :                           col_blk_size=nmos)
    2320             : 
    2321        4516 :       ALLOCATE (subm_main(ndomains))
    2322         550 :       CALL init_submatrices(subm_main)
    2323             :       !!!TRIM ALLOCATE(subm_trimmer(ndomains))
    2324             : 
    2325             :       CALL construct_submatrices(matrix_main, subm_main, &
    2326         550 :                                  dpattern, map, node_of_domain, select_row_col)
    2327             : 
    2328             :       !!!TRIM IF (matrix_trimmer_required) THEN
    2329             :       !!!TRIM    CALL construct_submatrices(matrix_trimmer,subm_trimmer,&
    2330             :       !!!TRIM            dpattern,map,node_of_domain,select_row)
    2331             :       !!!TRIM ENDIF
    2332             : 
    2333         550 :       IF (my_action .EQ. -1) THEN
    2334             :          ! project out the local occupied space
    2335             :          !tmp=MATMUL(subm_r(idomain)%mdata,Minv)
    2336             :          !Minv=MATMUL(tmp,subm_main(idomain)%mdata)
    2337             :          !subm_main(idomain)%mdata=subm_main(idomain)%mdata-&
    2338             :          !   Minv-TRANSPOSE(Minv)+MATMUL(Minv,TRANSPOSE(tmp))
    2339         222 :          ALLOCATE (subm_tmp(ndomains))
    2340         222 :          ALLOCATE (subm_tmp2(ndomains))
    2341          26 :          CALL init_submatrices(subm_tmp)
    2342          26 :          CALL init_submatrices(subm_tmp2)
    2343             :          CALL multiply_submatrices('N', 'N', 1.0_dp, subm_r_down, &
    2344          26 :                                    subm_s_inv, 0.0_dp, subm_tmp)
    2345             :          CALL multiply_submatrices('N', 'N', 1.0_dp, subm_tmp, &
    2346          26 :                                    subm_main, 0.0_dp, subm_tmp2)
    2347          26 :          CALL add_submatrices(1.0_dp, subm_main, -1.0_dp, subm_tmp2, 'N')
    2348          26 :          CALL add_submatrices(1.0_dp, subm_main, -1.0_dp, subm_tmp2, 'T')
    2349             :          CALL multiply_submatrices('N', 'T', 1.0_dp, subm_tmp2, &
    2350          26 :                                    subm_tmp, 1.0_dp, subm_main)
    2351          26 :          CALL release_submatrices(subm_tmp)
    2352          26 :          CALL release_submatrices(subm_tmp2)
    2353         196 :          DEALLOCATE (subm_tmp2)
    2354         196 :          DEALLOCATE (subm_tmp)
    2355             :       END IF
    2356             : 
    2357         550 :       IF (my_skip_inversion) THEN
    2358         316 :          CALL copy_submatrices(subm_main, preconditioner, .TRUE.)
    2359             :       ELSE
    2360             :          ! loop over domains - perform inversion
    2361        1284 :          DO idomain = 1, ndomains
    2362             : 
    2363             :             ! check if the submatrix exists
    2364        1284 :             IF (subm_main(idomain)%domain .GT. 0) THEN
    2365             : 
    2366             :                ! find sizes of MO submatrices
    2367         525 :                IF (idomain .EQ. 1) THEN
    2368             :                   index1_start = 1
    2369             :                ELSE
    2370         408 :                   index1_start = map%index1(idomain - 1)
    2371             :                END IF
    2372         525 :                index1_end = map%index1(idomain) - 1
    2373             : 
    2374         525 :                n_domain_mos = 0
    2375        2320 :                DO row = index1_start, index1_end
    2376        1795 :                   neighbor = map%pairs(row, 1)
    2377        2320 :                   n_domain_mos = n_domain_mos + nmos(neighbor)
    2378             :                END DO
    2379             : 
    2380         525 :                naos = subm_main(idomain)%nrows
    2381             :                !WRITE(*,*) "Domain, mo_self_and_neig, ao_domain: ", idomain, n_domain_mos, naos
    2382             : 
    2383        2100 :                ALLOCATE (Minv(naos, naos))
    2384             : 
    2385             :                !!!TRIM IF (my_use_trimmer) THEN
    2386             :                !!!TRIM    ! THIS IS SUPER EXPENSIVE (ELIMINATE)
    2387             :                !!!TRIM    ! trim the main matrix before inverting
    2388             :                !!!TRIM    ! assume that the trimmer columns are different (i.e. the main matrix is different for each MO)
    2389             :                !!!TRIM    allocate(tmp(naos,nmos(idomain)))
    2390             :                !!!TRIM    DO ii=1, nmos(idomain)
    2391             :                !!!TRIM       ! transform the main matrix using the trimmer for the current MO
    2392             :                !!!TRIM       DO jj=1, naos
    2393             :                !!!TRIM          DO kk=1, naos
    2394             :                !!!TRIM             Mstore(jj,kk)=sumb_main(idomain)%mdata(jj,kk)*&
    2395             :                !!!TRIM                subm_trimmer(idomain)%mdata(jj,ii)*&
    2396             :                !!!TRIM                subm_trimmer(idomain)%mdata(kk,ii)
    2397             :                !!!TRIM          ENDDO
    2398             :                !!!TRIM       ENDDO
    2399             :                !!!TRIM       ! invert the main matrix (exclude some eigenvalues, shift some)
    2400             :                !!!TRIM       CALL pseudo_invert_matrix(A=Mstore,Ainv=Minv,N=naos,method=1,&
    2401             :                !!!TRIM               !range1_thr=1.0E-9_dp,range2_thr=1.0E-9_dp,&
    2402             :                !!!TRIM               shift=1.0E-5_dp,&
    2403             :                !!!TRIM               range1=nmos(idomain),range2=nmos(idomain),&
    2404             :                !!!TRIM
    2405             :                !!!TRIM       ! apply the inverted matrix
    2406             :                !!!TRIM       ! RZK-warning this is only possible when the preconditioner is applied
    2407             :                !!!TRIM       tmp(:,ii)=MATMUL(Minv,subm_in(idomain)%mdata(:,ii))
    2408             :                !!!TRIM    ENDDO
    2409             :                !!!TRIM    subm_out=MATMUL(tmp,sigma)
    2410             :                !!!TRIM    deallocate(tmp)
    2411             :                !!!TRIM ELSE
    2412             : 
    2413         525 :                IF (PRESENT(bad_modes_projector_down)) THEN
    2414         180 :                   ALLOCATE (proj_array(naos, naos))
    2415             :                   CALL pseudo_invert_matrix(A=subm_main(idomain)%mdata, Ainv=Minv, N=naos, method=1, &
    2416             :                                             range1=nmos(idomain), range2=n_domain_mos, &
    2417             :                                             range1_thr=eps_zero_eigenvalues, &
    2418             :                                             bad_modes_projector_down=proj_array, &
    2419             :                                             s_inv_half=subm_s_inv_half(idomain)%mdata, &
    2420             :                                             s_half=subm_s_half(idomain)%mdata &
    2421          60 :                                             )
    2422             :                ELSE
    2423             :                   CALL pseudo_invert_matrix(A=subm_main(idomain)%mdata, Ainv=Minv, N=naos, method=1, &
    2424         465 :                                             range1=nmos(idomain), range2=n_domain_mos)
    2425             :                END IF
    2426             :                !!!TRIM ENDIF
    2427             : 
    2428         525 :                CALL copy_submatrices(subm_main(idomain), preconditioner(idomain), .FALSE.)
    2429         525 :                CALL copy_submatrix_data(Minv, preconditioner(idomain))
    2430         525 :                DEALLOCATE (Minv)
    2431             : 
    2432         525 :                IF (PRESENT(bad_modes_projector_down)) THEN
    2433          60 :                   CALL copy_submatrices(subm_main(idomain), bad_modes_projector_down(idomain), .FALSE.)
    2434          60 :                   CALL copy_submatrix_data(proj_array, bad_modes_projector_down(idomain))
    2435          60 :                   DEALLOCATE (proj_array)
    2436             :                END IF
    2437             : 
    2438             :             END IF ! submatrix for the domain exists
    2439             : 
    2440             :          END DO ! loop over domains
    2441             : 
    2442             :       END IF
    2443             : 
    2444         550 :       CALL release_submatrices(subm_main)
    2445        3416 :       DEALLOCATE (subm_main)
    2446             :       !DEALLOCATE(subm_s)
    2447             :       !DEALLOCATE(subm_r)
    2448             : 
    2449             :       !IF (matrix_r_required) THEN
    2450             :       !   CALL dbcsr_release(m_tmp_no_1)
    2451             :       !   CALL dbcsr_release(m_tmp_no_2)
    2452             :       !   CALL dbcsr_release(matrix_r)
    2453             :       !ENDIF
    2454             : 
    2455         550 :       CALL timestop(handle)
    2456             : 
    2457        1650 :    END SUBROUTINE construct_domain_preconditioner
    2458             : 
    2459             : ! **************************************************************************************************
    2460             : !> \brief Constructs S^(+1/2) and S^(-1/2) submatrices for each domain
    2461             : !> \param matrix_s ...
    2462             : !> \param subm_s_sqrt ...
    2463             : !> \param subm_s_sqrt_inv ...
    2464             : !> \param dpattern ...
    2465             : !> \param map ...
    2466             : !> \param node_of_domain ...
    2467             : !> \par History
    2468             : !>       2013.03 created [Rustam Z. Khaliullin]
    2469             : !> \author Rustam Z. Khaliullin
    2470             : ! **************************************************************************************************
    2471          40 :    SUBROUTINE construct_domain_s_sqrt(matrix_s, subm_s_sqrt, subm_s_sqrt_inv, &
    2472          40 :                                       dpattern, map, node_of_domain)
    2473             : 
    2474             :       TYPE(dbcsr_type), INTENT(IN)                       :: matrix_s
    2475             :       TYPE(domain_submatrix_type), DIMENSION(:), &
    2476             :          INTENT(INOUT)                                   :: subm_s_sqrt, subm_s_sqrt_inv
    2477             :       TYPE(dbcsr_type), INTENT(IN)                       :: dpattern
    2478             :       TYPE(domain_map_type), INTENT(IN)                  :: map
    2479             :       INTEGER, DIMENSION(:), INTENT(IN)                  :: node_of_domain
    2480             : 
    2481             :       CHARACTER(len=*), PARAMETER :: routineN = 'construct_domain_s_sqrt'
    2482             : 
    2483             :       INTEGER                                            :: handle, idomain, naos, ndomains
    2484          40 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: Ssqrt, Ssqrtinv
    2485             :       TYPE(domain_submatrix_type), ALLOCATABLE, &
    2486             :          DIMENSION(:)                                    :: subm_s
    2487             : 
    2488          40 :       CALL timeset(routineN, handle)
    2489             : 
    2490          40 :       ndomains = dbcsr_nblkcols_total(dpattern)
    2491          40 :       CPASSERT(SIZE(subm_s_sqrt) .EQ. ndomains)
    2492          40 :       CPASSERT(SIZE(subm_s_sqrt_inv) .EQ. ndomains)
    2493         376 :       ALLOCATE (subm_s(ndomains))
    2494          40 :       CALL init_submatrices(subm_s)
    2495             : 
    2496             :       CALL construct_submatrices(matrix_s, subm_s, &
    2497          40 :                                  dpattern, map, node_of_domain, select_row_col)
    2498             : 
    2499             :       ! loop over domains - perform inversion
    2500         296 :       DO idomain = 1, ndomains
    2501             : 
    2502             :          ! check if the submatrix exists
    2503         296 :          IF (subm_s(idomain)%domain .GT. 0) THEN
    2504             : 
    2505         128 :             naos = subm_s(idomain)%nrows
    2506             : 
    2507         512 :             ALLOCATE (Ssqrt(naos, naos))
    2508         384 :             ALLOCATE (Ssqrtinv(naos, naos))
    2509             : 
    2510             :             CALL matrix_sqrt(A=subm_s(idomain)%mdata, Asqrt=Ssqrt, Asqrtinv=Ssqrtinv, &
    2511         128 :                              N=naos)
    2512             : 
    2513         128 :             CALL copy_submatrices(subm_s(idomain), subm_s_sqrt(idomain), .FALSE.)
    2514         128 :             CALL copy_submatrix_data(Ssqrt, subm_s_sqrt(idomain))
    2515             : 
    2516         128 :             CALL copy_submatrices(subm_s(idomain), subm_s_sqrt_inv(idomain), .FALSE.)
    2517         128 :             CALL copy_submatrix_data(Ssqrtinv, subm_s_sqrt_inv(idomain))
    2518             : 
    2519         128 :             DEALLOCATE (Ssqrtinv)
    2520         128 :             DEALLOCATE (Ssqrt)
    2521             : 
    2522             :          END IF ! submatrix for the domain exists
    2523             : 
    2524             :       END DO ! loop over domains
    2525             : 
    2526          40 :       CALL release_submatrices(subm_s)
    2527         296 :       DEALLOCATE (subm_s)
    2528             : 
    2529          40 :       CALL timestop(handle)
    2530             : 
    2531          80 :    END SUBROUTINE construct_domain_s_sqrt
    2532             : 
    2533             : ! **************************************************************************************************
    2534             : !> \brief Constructs S_inv block for each domain
    2535             : !> \param matrix_s ...
    2536             : !> \param subm_s_inv ...
    2537             : !> \param dpattern ...
    2538             : !> \param map ...
    2539             : !> \param node_of_domain ...
    2540             : !> \par History
    2541             : !>       2013.02 created [Rustam Z. Khaliullin]
    2542             : !> \author Rustam Z. Khaliullin
    2543             : ! **************************************************************************************************
    2544          54 :    SUBROUTINE construct_domain_s_inv(matrix_s, subm_s_inv, dpattern, map, &
    2545          54 :                                      node_of_domain)
    2546             :       TYPE(dbcsr_type), INTENT(IN)                       :: matrix_s
    2547             :       TYPE(domain_submatrix_type), DIMENSION(:), &
    2548             :          INTENT(INOUT)                                   :: subm_s_inv
    2549             :       TYPE(dbcsr_type), INTENT(IN)                       :: dpattern
    2550             :       TYPE(domain_map_type), INTENT(IN)                  :: map
    2551             :       INTEGER, DIMENSION(:), INTENT(IN)                  :: node_of_domain
    2552             : 
    2553             :       CHARACTER(len=*), PARAMETER :: routineN = 'construct_domain_s_inv'
    2554             : 
    2555             :       INTEGER                                            :: handle, idomain, naos, ndomains
    2556          54 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: Sinv
    2557             :       TYPE(domain_submatrix_type), ALLOCATABLE, &
    2558             :          DIMENSION(:)                                    :: subm_s
    2559             : 
    2560          54 :       CALL timeset(routineN, handle)
    2561             : 
    2562          54 :       ndomains = dbcsr_nblkcols_total(dpattern)
    2563             : 
    2564          54 :       CPASSERT(SIZE(subm_s_inv) .EQ. ndomains)
    2565         520 :       ALLOCATE (subm_s(ndomains))
    2566          54 :       CALL init_submatrices(subm_s)
    2567             : 
    2568             :       CALL construct_submatrices(matrix_s, subm_s, &
    2569          54 :                                  dpattern, map, node_of_domain, select_row_col)
    2570             : 
    2571             :       ! loop over domains - perform inversion
    2572         412 :       DO idomain = 1, ndomains
    2573             : 
    2574             :          ! check if the submatrix exists
    2575         412 :          IF (subm_s(idomain)%domain .GT. 0) THEN
    2576             : 
    2577         179 :             naos = subm_s(idomain)%nrows
    2578             : 
    2579         716 :             ALLOCATE (Sinv(naos, naos))
    2580             : 
    2581             :             CALL pseudo_invert_matrix(A=subm_s(idomain)%mdata, Ainv=Sinv, N=naos, &
    2582         179 :                                       method=0)
    2583             : 
    2584         179 :             CALL copy_submatrices(subm_s(idomain), subm_s_inv(idomain), .FALSE.)
    2585         179 :             CALL copy_submatrix_data(Sinv, subm_s_inv(idomain))
    2586             : 
    2587         179 :             DEALLOCATE (Sinv)
    2588             : 
    2589             :          END IF ! submatrix for the domain exists
    2590             : 
    2591             :       END DO ! loop over domains
    2592             : 
    2593          54 :       CALL release_submatrices(subm_s)
    2594         412 :       DEALLOCATE (subm_s)
    2595             : 
    2596          54 :       CALL timestop(handle)
    2597             : 
    2598         108 :    END SUBROUTINE construct_domain_s_inv
    2599             : 
    2600             : ! **************************************************************************************************
    2601             : !> \brief Constructs subblocks of the covariant-covariant projectors (i.e. DM without spin factor)
    2602             : !> \param matrix_t ...
    2603             : !> \param matrix_sigma_inv ...
    2604             : !> \param matrix_s ...
    2605             : !> \param subm_r_down ...
    2606             : !> \param dpattern ...
    2607             : !> \param map ...
    2608             : !> \param node_of_domain ...
    2609             : !> \param filter_eps ...
    2610             : !> \par History
    2611             : !>       2013.02 created [Rustam Z. Khaliullin]
    2612             : !> \author Rustam Z. Khaliullin
    2613             : ! **************************************************************************************************
    2614          48 :    SUBROUTINE construct_domain_r_down(matrix_t, matrix_sigma_inv, matrix_s, &
    2615          24 :                                       subm_r_down, dpattern, map, node_of_domain, filter_eps)
    2616             : 
    2617             :       TYPE(dbcsr_type), INTENT(IN)                       :: matrix_t, matrix_sigma_inv, matrix_s
    2618             :       TYPE(domain_submatrix_type), DIMENSION(:), &
    2619             :          INTENT(INOUT)                                   :: subm_r_down
    2620             :       TYPE(dbcsr_type), INTENT(IN)                       :: dpattern
    2621             :       TYPE(domain_map_type), INTENT(IN)                  :: map
    2622             :       INTEGER, DIMENSION(:), INTENT(IN)                  :: node_of_domain
    2623             :       REAL(KIND=dp)                                      :: filter_eps
    2624             : 
    2625             :       CHARACTER(len=*), PARAMETER :: routineN = 'construct_domain_r_down'
    2626             : 
    2627             :       INTEGER                                            :: handle, ndomains
    2628             :       TYPE(dbcsr_type)                                   :: m_tmp_no_1, m_tmp_no_2, matrix_r
    2629             : 
    2630          24 :       CALL timeset(routineN, handle)
    2631             : 
    2632             :       ! compute the density matrix in the COVARIANT representation
    2633             :       CALL dbcsr_create(matrix_r, &
    2634             :                         template=matrix_s, &
    2635          24 :                         matrix_type=dbcsr_type_symmetric)
    2636             :       CALL dbcsr_create(m_tmp_no_1, &
    2637             :                         template=matrix_t, &
    2638          24 :                         matrix_type=dbcsr_type_no_symmetry)
    2639             :       CALL dbcsr_create(m_tmp_no_2, &
    2640             :                         template=matrix_t, &
    2641          24 :                         matrix_type=dbcsr_type_no_symmetry)
    2642             : 
    2643             :       CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_s, matrix_t, &
    2644          24 :                           0.0_dp, m_tmp_no_1, filter_eps=filter_eps)
    2645             :       CALL dbcsr_multiply("N", "N", 1.0_dp, m_tmp_no_1, matrix_sigma_inv, &
    2646          24 :                           0.0_dp, m_tmp_no_2, filter_eps=filter_eps)
    2647             :       CALL dbcsr_multiply("N", "T", 1.0_dp, m_tmp_no_2, m_tmp_no_1, &
    2648          24 :                           0.0_dp, matrix_r, filter_eps=filter_eps)
    2649             : 
    2650          24 :       CALL dbcsr_release(m_tmp_no_1)
    2651          24 :       CALL dbcsr_release(m_tmp_no_2)
    2652             : 
    2653          24 :       ndomains = dbcsr_nblkcols_total(dpattern)
    2654          24 :       CPASSERT(SIZE(subm_r_down) .EQ. ndomains)
    2655             : 
    2656             :       CALL construct_submatrices(matrix_r, subm_r_down, &
    2657          24 :                                  dpattern, map, node_of_domain, select_row_col)
    2658             : 
    2659          24 :       CALL dbcsr_release(matrix_r)
    2660             : 
    2661          24 :       CALL timestop(handle)
    2662             : 
    2663          24 :    END SUBROUTINE construct_domain_r_down
    2664             : 
    2665             : ! **************************************************************************************************
    2666             : !> \brief Finds the square root of a matrix and its inverse
    2667             : !> \param A ...
    2668             : !> \param Asqrt ...
    2669             : !> \param Asqrtinv ...
    2670             : !> \param N ...
    2671             : !> \par History
    2672             : !>       2013.03 created [Rustam Z. Khaliullin]
    2673             : !> \author Rustam Z. Khaliullin
    2674             : ! **************************************************************************************************
    2675         128 :    SUBROUTINE matrix_sqrt(A, Asqrt, Asqrtinv, N)
    2676             : 
    2677             :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: A
    2678             :       REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT)      :: Asqrt, Asqrtinv
    2679             :       INTEGER, INTENT(IN)                                :: N
    2680             : 
    2681             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'matrix_sqrt'
    2682             : 
    2683             :       INTEGER                                            :: handle, INFO, jj, LWORK, unit_nr
    2684         128 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: eigenvalues, WORK
    2685         128 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: test, testN
    2686             :       TYPE(cp_logger_type), POINTER                      :: logger
    2687             : 
    2688         128 :       CALL timeset(routineN, handle)
    2689             : 
    2690      585400 :       Asqrtinv = A
    2691         128 :       INFO = 0
    2692             : 
    2693             :       ! get a useful unit_nr
    2694         128 :       logger => cp_get_default_logger()
    2695         128 :       IF (logger%para_env%is_source()) THEN
    2696          65 :          unit_nr = cp_logger_get_default_unit_nr(logger, local=.TRUE.)
    2697             :       ELSE
    2698             :          unit_nr = -1
    2699             :       END IF
    2700             : 
    2701             :       !CALL dpotrf('L', N, Ainv, N, INFO )
    2702             :       !IF( INFO.NE.0 ) THEN
    2703             :       !   CPErrorMessage(cp_failure_level,routineP,"DPOTRF failed")
    2704             :       !   CPPrecondition(.FALSE.,cp_failure_level,routineP,failure)
    2705             :       !END IF
    2706             :       !CALL dpotri('L', N, Ainv, N, INFO )
    2707             :       !IF( INFO.NE.0 ) THEN
    2708             :       !   CPErrorMessage(cp_failure_level,routineP,"DPOTRI failed")
    2709             :       !   CPPrecondition(.FALSE.,cp_failure_level,routineP,failure)
    2710             :       !END IF
    2711             :       !! complete the matrix
    2712             :       !DO ii=1,N
    2713             :       !   DO jj=ii+1,N
    2714             :       !      Ainv(ii,jj)=Ainv(jj,ii)
    2715             :       !   ENDDO
    2716             :       !   !WRITE(*,'(100F13.9)') Ainv(ii,:)
    2717             :       !ENDDO
    2718             : 
    2719             :       ! diagonalize first
    2720         384 :       ALLOCATE (eigenvalues(N))
    2721             :       ! Query the optimal workspace for dsyev
    2722         128 :       LWORK = -1
    2723         128 :       ALLOCATE (WORK(MAX(1, LWORK)))
    2724         128 :       CALL dsyev('V', 'L', N, Asqrtinv, N, eigenvalues, WORK, LWORK, INFO)
    2725         128 :       LWORK = INT(WORK(1))
    2726         128 :       DEALLOCATE (WORK)
    2727             :       ! Allocate the workspace and solve the eigenproblem
    2728         384 :       ALLOCATE (WORK(MAX(1, LWORK)))
    2729         128 :       CALL dsyev('V', 'L', N, Asqrtinv, N, eigenvalues, WORK, LWORK, INFO)
    2730         128 :       IF (INFO .NE. 0) THEN
    2731           0 :          IF (unit_nr > 0) WRITE (unit_nr, *) 'DSYEV ERROR MESSAGE: ', INFO
    2732           0 :          CPABORT("DSYEV failed")
    2733             :       END IF
    2734         128 :       DEALLOCATE (WORK)
    2735             : 
    2736             :       ! take functions of eigenvalues and use eigenvectors to compute the matrix function
    2737             :       ! first sqrt
    2738         512 :       ALLOCATE (test(N, N))
    2739        6242 :       DO jj = 1, N
    2740      585400 :          test(jj, :) = Asqrtinv(:, jj)*SQRT(eigenvalues(jj))
    2741             :       END DO
    2742         384 :       ALLOCATE (testN(N, N))
    2743      899950 :       testN(:, :) = MATMUL(Asqrtinv, test)
    2744      585400 :       Asqrt = testN
    2745             :       ! now, sqrt_inv
    2746        6242 :       DO jj = 1, N
    2747      585400 :          test(jj, :) = Asqrtinv(:, jj)/SQRT(eigenvalues(jj))
    2748             :       END DO
    2749      899950 :       testN(:, :) = MATMUL(Asqrtinv, test)
    2750      585400 :       Asqrtinv = testN
    2751         128 :       DEALLOCATE (test, testN)
    2752             : 
    2753         128 :       DEALLOCATE (eigenvalues)
    2754             : 
    2755             : !!!    ! compute the error
    2756             : !!!    allocate(test(N,N))
    2757             : !!!    test=MATMUL(Ainv,A)
    2758             : !!!    DO ii=1,N
    2759             : !!!       test(ii,ii)=test(ii,ii)-1.0_dp
    2760             : !!!    ENDDO
    2761             : !!!    test_error=0.0_dp
    2762             : !!!    DO ii=1,N
    2763             : !!!       DO jj=1,N
    2764             : !!!          test_error=test_error+test(jj,ii)*test(jj,ii)
    2765             : !!!       ENDDO
    2766             : !!!    ENDDO
    2767             : !!!    WRITE(*,*) "Inversion error: ", SQRT(test_error)
    2768             : !!!    deallocate(test)
    2769             : 
    2770         128 :       CALL timestop(handle)
    2771             : 
    2772         128 :    END SUBROUTINE matrix_sqrt
    2773             : 
    2774             : ! **************************************************************************************************
    2775             : !> \brief Inverts a matrix using a requested method
    2776             : !>         0. Cholesky factorization
    2777             : !>         1. Diagonalization
    2778             : !> \param A ...
    2779             : !> \param Ainv ...
    2780             : !> \param N ...
    2781             : !> \param method ...
    2782             : !> \param range1 ...
    2783             : !> \param range2 ...
    2784             : !> \param range1_thr ...
    2785             : !> \param shift ...
    2786             : !> \param bad_modes_projector_down ...
    2787             : !> \param s_inv_half ...
    2788             : !> \param s_half ...
    2789             : !> \par History
    2790             : !>       2012.04 created [Rustam Z. Khaliullin]
    2791             : !> \author Rustam Z. Khaliullin
    2792             : ! **************************************************************************************************
    2793        1023 :    SUBROUTINE pseudo_invert_matrix(A, Ainv, N, method, range1, range2, range1_thr, &
    2794        2046 :                                    shift, bad_modes_projector_down, s_inv_half, s_half)
    2795             : 
    2796             :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: A
    2797             :       REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT)      :: Ainv
    2798             :       INTEGER, INTENT(IN)                                :: N, method
    2799             :       INTEGER, INTENT(IN), OPTIONAL                      :: range1, range2
    2800             :       REAL(KIND=dp), INTENT(IN), OPTIONAL                :: range1_thr, shift
    2801             :       REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT), &
    2802             :          OPTIONAL                                        :: bad_modes_projector_down
    2803             :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN), &
    2804             :          OPTIONAL                                        :: s_inv_half, s_half
    2805             : 
    2806             :       CHARACTER(len=*), PARAMETER :: routineN = 'pseudo_invert_matrix'
    2807             : 
    2808             :       INTEGER                                            :: handle, INFO, jj, LWORK, range1_eiv, &
    2809             :                                                             range2_eiv, range3_eiv, unit_nr
    2810             :       LOGICAL                                            :: use_both, use_ranges_only, use_thr_only
    2811             :       REAL(KIND=dp)                                      :: my_shift
    2812        1023 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: eigenvalues, WORK
    2813        1023 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: temp1, temp2, temp3, temp4
    2814             :       TYPE(cp_logger_type), POINTER                      :: logger
    2815             : 
    2816        1023 :       CALL timeset(routineN, handle)
    2817             : 
    2818             :       ! get a useful unit_nr
    2819        1023 :       logger => cp_get_default_logger()
    2820        1023 :       IF (logger%para_env%is_source()) THEN
    2821         514 :          unit_nr = cp_logger_get_default_unit_nr(logger, local=.TRUE.)
    2822             :       ELSE
    2823             :          unit_nr = -1
    2824             :       END IF
    2825             : 
    2826        1023 :       IF (method .EQ. 1) THEN
    2827             : 
    2828         844 :          IF ((PRESENT(range1) .AND. (.NOT. PRESENT(range2))) .OR. (PRESENT(range2) .AND. (.NOT. PRESENT(range1)))) THEN
    2829           0 :             CPABORT("range1 and range2 must be provided together")
    2830             :          END IF
    2831             : 
    2832         844 :          IF (PRESENT(range1) .AND. PRESENT(range1_thr)) THEN
    2833             :             use_both = .TRUE.
    2834             :             use_thr_only = .FALSE.
    2835             :             use_ranges_only = .FALSE.
    2836             :          ELSE
    2837         784 :             use_both = .FALSE.
    2838             : 
    2839         784 :             IF (PRESENT(range1)) THEN
    2840             :                use_ranges_only = .TRUE.
    2841             :             ELSE
    2842           0 :                use_ranges_only = .FALSE.
    2843             :             END IF
    2844             : 
    2845         784 :             IF (PRESENT(range1_thr)) THEN
    2846             :                use_thr_only = .TRUE.
    2847             :             ELSE
    2848         784 :                use_thr_only = .FALSE.
    2849             :             END IF
    2850             : 
    2851             :          END IF
    2852             : 
    2853         844 :          IF ((PRESENT(s_half) .AND. (.NOT. PRESENT(s_inv_half))) .OR. (PRESENT(s_inv_half) .AND. (.NOT. PRESENT(s_half)))) THEN
    2854           0 :             CPABORT("Domain overlap matrix missing")
    2855             :          END IF
    2856             :       END IF
    2857             : 
    2858        1023 :       my_shift = 0.0_dp
    2859        1023 :       IF (PRESENT(shift)) THEN
    2860         319 :          my_shift = shift
    2861             :       END IF
    2862             : 
    2863     2592719 :       Ainv = A
    2864        1023 :       INFO = 0
    2865             : 
    2866         179 :       SELECT CASE (method)
    2867             :       CASE (0) ! Inversion via cholesky factorization
    2868         179 :          CALL invmat_symm(Ainv)
    2869             :       CASE (1)
    2870             : 
    2871             :          ! diagonalize first
    2872        2532 :          ALLOCATE (eigenvalues(N))
    2873        3376 :          ALLOCATE (temp1(N, N))
    2874        2532 :          ALLOCATE (temp4(N, N))
    2875         844 :          IF (PRESENT(s_inv_half)) THEN
    2876          60 :             CALL dsymm('L', 'U', N, N, 1.0_dp, s_inv_half, N, A, N, 0.0_dp, temp1, N)
    2877          60 :             CALL dsymm('R', 'U', N, N, 1.0_dp, s_inv_half, N, temp1, N, 0.0_dp, Ainv, N)
    2878             :          END IF
    2879             :          ! Query the optimal workspace for dsyev
    2880         844 :          LWORK = -1
    2881         844 :          ALLOCATE (WORK(MAX(1, LWORK)))
    2882         844 :          CALL dsyev('V', 'L', N, Ainv, N, eigenvalues, WORK, LWORK, INFO)
    2883             : 
    2884         844 :          LWORK = INT(WORK(1))
    2885         844 :          DEALLOCATE (WORK)
    2886             :          ! Allocate the workspace and solve the eigenproblem
    2887        2532 :          ALLOCATE (WORK(MAX(1, LWORK)))
    2888         844 :          CALL dsyev('V', 'L', N, Ainv, N, eigenvalues, WORK, LWORK, INFO)
    2889             : 
    2890         844 :          IF (INFO .NE. 0) THEN
    2891           0 :             IF (unit_nr > 0) WRITE (unit_nr, *) 'EIGENSYSTEM ERROR MESSAGE: ', INFO
    2892           0 :             CPABORT("Eigenproblem routine failed")
    2893             :          END IF
    2894         844 :          DEALLOCATE (WORK)
    2895             : 
    2896             :          !WRITE(*,*) "EIGENVALS: "
    2897             :          !WRITE(*,'(4F13.9)') eigenvalues(:)
    2898             : 
    2899             :          ! invert eigenvalues and use eigenvectors to compute pseudo Ainv
    2900             :          ! project out near-zero eigenvalue modes
    2901        2532 :          ALLOCATE (temp2(N, N))
    2902         964 :          IF (PRESENT(bad_modes_projector_down)) ALLOCATE (temp3(N, N))
    2903     2015494 :          temp2(1:N, 1:N) = Ainv(1:N, 1:N)
    2904             : 
    2905         844 :          range1_eiv = 0
    2906         844 :          range2_eiv = 0
    2907         844 :          range3_eiv = 0
    2908             : 
    2909         844 :          IF (use_both) THEN
    2910        1116 :             DO jj = 1, N
    2911        1116 :                IF ((jj .LE. range2) .AND. (eigenvalues(jj) .LT. range1_thr)) THEN
    2912        9274 :                   temp1(jj, :) = temp2(:, jj)*0.0_dp
    2913        9274 :                   IF (PRESENT(bad_modes_projector_down)) temp3(jj, :) = Ainv(:, jj)*1.0_dp
    2914         454 :                   range1_eiv = range1_eiv + 1
    2915             :                ELSE
    2916       17528 :                   temp1(jj, :) = temp2(:, jj)/(eigenvalues(jj) + my_shift)
    2917       17528 :                   IF (PRESENT(bad_modes_projector_down)) temp3(jj, :) = Ainv(:, jj)*0.0_dp
    2918         602 :                   range2_eiv = range2_eiv + 1
    2919             :                END IF
    2920             :             END DO
    2921             :          ELSE
    2922         784 :             IF (use_ranges_only) THEN
    2923       34678 :                DO jj = 1, N
    2924       34678 :                   IF (jj .LE. range1) THEN
    2925      152199 :                      temp1(jj, :) = temp2(:, jj)*0.0_dp
    2926        3173 :                      IF (PRESENT(bad_modes_projector_down)) temp3(jj, :) = Ainv(:, jj)*1.0_dp
    2927        3173 :                      range1_eiv = range1_eiv + 1
    2928       30721 :                   ELSE IF (jj .LE. range2) THEN
    2929      256093 :                      temp1(jj, :) = temp2(:, jj)*1.0_dp
    2930        4129 :                      IF (PRESENT(bad_modes_projector_down)) temp3(jj, :) = Ainv(:, jj)*1.0_dp
    2931        4129 :                      range2_eiv = range2_eiv + 1
    2932             :                   ELSE
    2933     1579556 :                      temp1(jj, :) = temp2(:, jj)/(eigenvalues(jj) + my_shift)
    2934       26592 :                      IF (PRESENT(bad_modes_projector_down)) temp3(jj, :) = Ainv(:, jj)*0.0_dp
    2935       26592 :                      range3_eiv = range3_eiv + 1
    2936             :                   END IF
    2937             :                END DO
    2938           0 :             ELSE IF (use_thr_only) THEN
    2939           0 :                DO jj = 1, N
    2940           0 :                   IF (eigenvalues(jj) .LT. range1_thr) THEN
    2941           0 :                      temp1(jj, :) = temp2(:, jj)*0.0_dp
    2942           0 :                      IF (PRESENT(bad_modes_projector_down)) temp3(jj, :) = Ainv(:, jj)*1.0_dp
    2943           0 :                      range1_eiv = range1_eiv + 1
    2944             :                   ELSE
    2945           0 :                      temp1(jj, :) = temp2(:, jj)/(eigenvalues(jj) + my_shift)
    2946           0 :                      IF (PRESENT(bad_modes_projector_down)) temp3(jj, :) = Ainv(:, jj)*0.0_dp
    2947           0 :                      range2_eiv = range2_eiv + 1
    2948             :                   END IF
    2949             :                END DO
    2950             :             ELSE ! no ranges, no thresholds
    2951           0 :                CPABORT("Invert using Cholesky. It would be faster.")
    2952             :             END IF
    2953             :          END IF
    2954             :          !WRITE(*,*) ' EIV RANGES: ', range1_eiv, range2_eiv, range3_eiv
    2955         844 :          IF (PRESENT(bad_modes_projector_down)) THEN
    2956          60 :             IF (PRESENT(s_half)) THEN
    2957          60 :                CALL dsymm('L', 'U', N, N, 1.0_dp, s_half, N, temp2, N, 0.0_dp, Ainv, N)
    2958          60 :                CALL dsymm('R', 'U', N, N, 1.0_dp, s_half, N, temp3, N, 0.0_dp, temp4, N)
    2959          60 :                CALL dgemm('N', 'N', N, N, N, 1.0_dp, Ainv, N, temp4, N, 0.0_dp, bad_modes_projector_down, N)
    2960             :             ELSE
    2961           0 :                CALL dgemm('N', 'N', N, N, N, 1.0_dp, temp2, N, temp3, N, 0.0_dp, bad_modes_projector_down, N)
    2962             :             END IF
    2963             :          END IF
    2964             : 
    2965         844 :          IF (PRESENT(s_inv_half)) THEN
    2966          60 :             CALL dsymm('L', 'U', N, N, 1.0_dp, s_inv_half, N, temp2, N, 0.0_dp, temp4, N)
    2967          60 :             CALL dsymm('R', 'U', N, N, 1.0_dp, s_inv_half, N, temp1, N, 0.0_dp, temp2, N)
    2968          60 :             CALL dgemm('N', 'N', N, N, N, 1.0_dp, temp4, N, temp2, N, 0.0_dp, Ainv, N)
    2969             :          ELSE
    2970         784 :             CALL dgemm('N', 'N', N, N, N, 1.0_dp, temp2, N, temp1, N, 0.0_dp, Ainv, N)
    2971             :          END IF
    2972         844 :          DEALLOCATE (temp1, temp2, temp4)
    2973         844 :          IF (PRESENT(bad_modes_projector_down)) DEALLOCATE (temp3)
    2974         844 :          DEALLOCATE (eigenvalues)
    2975             : 
    2976             :       CASE DEFAULT
    2977             : 
    2978        1023 :          CPABORT("Illegal method selected for matrix inversion")
    2979             : 
    2980             :       END SELECT
    2981             : 
    2982             :       !! compute the inversion error
    2983             :       !allocate(temp1(N,N))
    2984             :       !temp1=MATMUL(Ainv,A)
    2985             :       !DO ii=1,N
    2986             :       !   temp1(ii,ii)=temp1(ii,ii)-1.0_dp
    2987             :       !ENDDO
    2988             :       !temp1_error=0.0_dp
    2989             :       !DO ii=1,N
    2990             :       !   DO jj=1,N
    2991             :       !      temp1_error=temp1_error+temp1(jj,ii)*temp1(jj,ii)
    2992             :       !   ENDDO
    2993             :       !ENDDO
    2994             :       !WRITE(*,*) "Inversion error: ", SQRT(temp1_error)
    2995             :       !deallocate(temp1)
    2996             : 
    2997        1023 :       CALL timestop(handle)
    2998             : 
    2999        1023 :    END SUBROUTINE pseudo_invert_matrix
    3000             : 
    3001             : ! **************************************************************************************************
    3002             : !> \brief Find matrix power using diagonalization
    3003             : !> \param A ...
    3004             : !> \param Apow ...
    3005             : !> \param power ...
    3006             : !> \param N ...
    3007             : !> \param range1 ...
    3008             : !> \param range1_thr ...
    3009             : !> \param shift ...
    3010             : !> \par History
    3011             : !>       2012.04 created [Rustam Z. Khaliullin]
    3012             : !> \author Rustam Z. Khaliullin
    3013             : ! **************************************************************************************************
    3014           0 :    SUBROUTINE pseudo_matrix_power(A, Apow, power, N, range1, range1_thr, shift)
    3015             : 
    3016             :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: A
    3017             :       REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT)      :: Apow
    3018             :       REAL(KIND=dp), INTENT(IN)                          :: power
    3019             :       INTEGER, INTENT(IN)                                :: N
    3020             :       INTEGER, INTENT(IN), OPTIONAL                      :: range1
    3021             :       REAL(KIND=dp), INTENT(IN), OPTIONAL                :: range1_thr, shift
    3022             : 
    3023             :       CHARACTER(len=*), PARAMETER :: routineN = 'pseudo_matrix_power'
    3024             : 
    3025             :       INTEGER                                            :: handle, INFO, jj, LWORK, range1_eiv, &
    3026             :                                                             range2_eiv, unit_nr
    3027             :       LOGICAL                                            :: use_both, use_ranges, use_thr
    3028             :       REAL(KIND=dp)                                      :: my_shift
    3029           0 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: eigenvalues, WORK
    3030           0 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: temp1, temp2
    3031             :       TYPE(cp_logger_type), POINTER                      :: logger
    3032             : 
    3033           0 :       CALL timeset(routineN, handle)
    3034             : 
    3035             :       ! get a useful unit_nr
    3036           0 :       logger => cp_get_default_logger()
    3037           0 :       IF (logger%para_env%is_source()) THEN
    3038           0 :          unit_nr = cp_logger_get_default_unit_nr(logger, local=.TRUE.)
    3039             :       ELSE
    3040             :          unit_nr = -1
    3041             :       END IF
    3042             : 
    3043           0 :       IF (PRESENT(range1) .AND. PRESENT(range1_thr)) THEN
    3044             :          use_both = .TRUE.
    3045             :       ELSE
    3046           0 :          use_both = .FALSE.
    3047           0 :          IF (PRESENT(range1)) THEN
    3048             :             use_ranges = .TRUE.
    3049             :          ELSE
    3050           0 :             use_ranges = .FALSE.
    3051           0 :             IF (PRESENT(range1_thr)) THEN
    3052             :                use_thr = .TRUE.
    3053             :             ELSE
    3054           0 :                use_thr = .FALSE.
    3055             :             END IF
    3056             :          END IF
    3057             :       END IF
    3058             : 
    3059           0 :       my_shift = 0.0_dp
    3060           0 :       IF (PRESENT(shift)) THEN
    3061           0 :          my_shift = shift
    3062             :       END IF
    3063             : 
    3064           0 :       Apow = A
    3065           0 :       INFO = 0
    3066             : 
    3067             :       ! diagonalize first
    3068           0 :       ALLOCATE (eigenvalues(N))
    3069           0 :       ALLOCATE (temp1(N, N))
    3070             : 
    3071             :       ! Query the optimal workspace for dsyev
    3072           0 :       LWORK = -1
    3073           0 :       ALLOCATE (WORK(MAX(1, LWORK)))
    3074           0 :       CALL dsyev('V', 'L', N, Apow, N, eigenvalues, WORK, LWORK, INFO)
    3075             : 
    3076           0 :       LWORK = INT(WORK(1))
    3077           0 :       DEALLOCATE (WORK)
    3078             :       ! Allocate the workspace and solve the eigenproblem
    3079           0 :       ALLOCATE (WORK(MAX(1, LWORK)))
    3080           0 :       CALL dsyev('V', 'L', N, Apow, N, eigenvalues, WORK, LWORK, INFO)
    3081             : 
    3082           0 :       IF (INFO .NE. 0) THEN
    3083           0 :          IF (unit_nr > 0) WRITE (unit_nr, *) 'EIGENSYSTEM ERROR MESSAGE: ', INFO
    3084           0 :          CPABORT("Eigenproblem routine failed")
    3085             :       END IF
    3086           0 :       DEALLOCATE (WORK)
    3087             : 
    3088             :       !WRITE(*,*) "EIGENVALS: "
    3089             :       !WRITE(*,'(4F13.9)') eigenvalues(:)
    3090             : 
    3091             :       ! invert eigenvalues and use eigenvectors to compute pseudo Ainv
    3092             :       ! project out near-zero eigenvalue modes
    3093           0 :       ALLOCATE (temp2(N, N))
    3094             : 
    3095           0 :       temp2(1:N, 1:N) = Apow(1:N, 1:N)
    3096             : 
    3097           0 :       range1_eiv = 0
    3098           0 :       range2_eiv = 0
    3099             : 
    3100           0 :       IF (use_both) THEN
    3101           0 :          DO jj = 1, N
    3102           0 :             IF ((jj .LE. range1) .AND. (eigenvalues(jj) .LT. range1_thr)) THEN
    3103           0 :                temp1(jj, :) = temp2(:, jj)*0.0_dp
    3104           0 :                range1_eiv = range1_eiv + 1
    3105             :             ELSE
    3106           0 :                temp1(jj, :) = temp2(:, jj)*((eigenvalues(jj) + my_shift)**power)
    3107             :             END IF
    3108             :          END DO
    3109             :       ELSE
    3110           0 :          IF (use_ranges) THEN
    3111           0 :             DO jj = 1, N
    3112           0 :                IF (jj .LE. range1) THEN
    3113           0 :                   temp1(jj, :) = temp2(:, jj)*0.0_dp
    3114           0 :                   range1_eiv = range1_eiv + 1
    3115             :                ELSE
    3116           0 :                   temp1(jj, :) = temp2(:, jj)*((eigenvalues(jj) + my_shift)**power)
    3117             :                END IF
    3118             :             END DO
    3119             :          ELSE
    3120           0 :             IF (use_thr) THEN
    3121           0 :                DO jj = 1, N
    3122           0 :                   IF (eigenvalues(jj) .LT. range1_thr) THEN
    3123           0 :                      temp1(jj, :) = temp2(:, jj)*0.0_dp
    3124             : 
    3125           0 :                      range1_eiv = range1_eiv + 1
    3126             :                   ELSE
    3127           0 :                      temp1(jj, :) = temp2(:, jj)*((eigenvalues(jj) + my_shift)**power)
    3128             :                   END IF
    3129             :                END DO
    3130             :             ELSE
    3131           0 :                DO jj = 1, N
    3132           0 :                   temp1(jj, :) = temp2(:, jj)*((eigenvalues(jj) + my_shift)**power)
    3133             :                END DO
    3134             :             END IF
    3135             :          END IF
    3136             :       END IF
    3137             :       !WRITE(*,*) ' EIV RANGES: ', range1_eiv, range2_eiv, range3_eiv
    3138           0 :       Apow = MATMUL(temp2, temp1)
    3139           0 :       DEALLOCATE (temp1, temp2)
    3140           0 :       DEALLOCATE (eigenvalues)
    3141             : 
    3142           0 :       CALL timestop(handle)
    3143             : 
    3144           0 :    END SUBROUTINE pseudo_matrix_power
    3145             : 
    3146             : ! **************************************************************************************************
    3147             : !> \brief Load balancing of the submatrix computations
    3148             : !> \param almo_scf_env ...
    3149             : !> \par History
    3150             : !>       2013.02 created [Rustam Z. Khaliullin]
    3151             : !> \author Rustam Z. Khaliullin
    3152             : ! **************************************************************************************************
    3153         116 :    SUBROUTINE distribute_domains(almo_scf_env)
    3154             : 
    3155             :       TYPE(almo_scf_env_type), INTENT(INOUT)             :: almo_scf_env
    3156             : 
    3157             :       CHARACTER(len=*), PARAMETER :: routineN = 'distribute_domains'
    3158             : 
    3159             :       INTEGER                                            :: handle, idomain, least_loaded, nao, &
    3160             :                                                             ncpus, ndomains
    3161         116 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: index0
    3162         116 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: cpu_load, domain_load
    3163             :       TYPE(dbcsr_distribution_type)                      :: dist
    3164             : 
    3165         116 :       CALL timeset(routineN, handle)
    3166             : 
    3167         116 :       ndomains = almo_scf_env%ndomains
    3168         116 :       CALL dbcsr_get_info(almo_scf_env%matrix_s(1), distribution=dist)
    3169         116 :       CALL dbcsr_distribution_get(dist, numnodes=ncpus)
    3170             : 
    3171         348 :       ALLOCATE (domain_load(ndomains))
    3172         926 :       DO idomain = 1, ndomains
    3173         810 :          nao = almo_scf_env%nbasis_of_domain(idomain)
    3174         926 :          domain_load(idomain) = (nao*nao*nao)*1.0_dp
    3175             :       END DO
    3176             : 
    3177         348 :       ALLOCATE (index0(ndomains))
    3178             : 
    3179         116 :       CALL sort(domain_load, ndomains, index0)
    3180             : 
    3181         348 :       ALLOCATE (cpu_load(ncpus))
    3182         348 :       cpu_load(:) = 0.0_dp
    3183             : 
    3184         926 :       DO idomain = 1, ndomains
    3185        3240 :          least_loaded = MINLOC(cpu_load, 1)
    3186         810 :          cpu_load(least_loaded) = cpu_load(least_loaded) + domain_load(idomain)
    3187         926 :          almo_scf_env%cpu_of_domain(index0(idomain)) = least_loaded - 1
    3188             :       END DO
    3189             : 
    3190         116 :       DEALLOCATE (cpu_load)
    3191         116 :       DEALLOCATE (index0)
    3192         116 :       DEALLOCATE (domain_load)
    3193             : 
    3194         116 :       CALL timestop(handle)
    3195             : 
    3196         116 :    END SUBROUTINE distribute_domains
    3197             : 
    3198             : ! **************************************************************************************************
    3199             : !> \brief Tests construction and release of domain submatrices
    3200             : !> \param matrix_no ...
    3201             : !> \param dpattern ...
    3202             : !> \param map ...
    3203             : !> \param node_of_domain ...
    3204             : !> \par History
    3205             : !>       2013.01 created [Rustam Z. Khaliullin]
    3206             : !> \author Rustam Z. Khaliullin
    3207             : ! **************************************************************************************************
    3208           0 :    SUBROUTINE construct_test(matrix_no, dpattern, map, node_of_domain)
    3209             : 
    3210             :       TYPE(dbcsr_type), INTENT(IN)                       :: matrix_no, dpattern
    3211             :       TYPE(domain_map_type), INTENT(IN)                  :: map
    3212             :       INTEGER, DIMENSION(:), INTENT(IN)                  :: node_of_domain
    3213             : 
    3214             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'construct_test'
    3215             : 
    3216             :       INTEGER                                            :: GroupID, handle, ndomains
    3217             :       TYPE(dbcsr_type)                                   :: copy1
    3218             :       TYPE(domain_submatrix_type), ALLOCATABLE, &
    3219           0 :          DIMENSION(:)                                    :: subm_nn, subm_no
    3220             :       TYPE(mp_comm_type)                                 :: group
    3221             : 
    3222           0 :       CALL timeset(routineN, handle)
    3223             : 
    3224           0 :       ndomains = dbcsr_nblkcols_total(dpattern)
    3225           0 :       CALL dbcsr_get_info(dpattern, group=GroupID)
    3226           0 :       CALL group%set_handle(groupid)
    3227             : 
    3228           0 :       ALLOCATE (subm_no(ndomains), subm_nn(ndomains))
    3229           0 :       CALL init_submatrices(subm_no)
    3230           0 :       CALL init_submatrices(subm_nn)
    3231             : 
    3232             :       !CALL dbcsr_print(matrix_nn)
    3233             :       !CALL construct_submatrices(matrix_nn,subm_nn,dpattern,map,select_row_col)
    3234             :       !CALL print_submatrices(subm_nn,Group)
    3235             : 
    3236             :       !CALL dbcsr_print(matrix_no)
    3237           0 :       CALL construct_submatrices(matrix_no, subm_no, dpattern, map, node_of_domain, select_row)
    3238           0 :       CALL print_submatrices(subm_no, group)
    3239             : 
    3240           0 :       CALL dbcsr_create(copy1, template=matrix_no)
    3241           0 :       CALL dbcsr_copy(copy1, matrix_no)
    3242           0 :       CALL dbcsr_print(copy1)
    3243           0 :       CALL construct_dbcsr_from_submatrices(copy1, subm_no, dpattern)
    3244           0 :       CALL dbcsr_print(copy1)
    3245           0 :       CALL dbcsr_release(copy1)
    3246             : 
    3247           0 :       CALL release_submatrices(subm_no)
    3248           0 :       CALL release_submatrices(subm_nn)
    3249           0 :       DEALLOCATE (subm_no, subm_nn)
    3250             : 
    3251           0 :       CALL timestop(handle)
    3252             : 
    3253           0 :    END SUBROUTINE construct_test
    3254             : 
    3255             : ! **************************************************************************************************
    3256             : !> \brief create the initial guess for XALMOs
    3257             : !> \param m_guess ...
    3258             : !> \param m_t_in ...
    3259             : !> \param m_t0 ...
    3260             : !> \param m_quench_t ...
    3261             : !> \param m_overlap ...
    3262             : !> \param m_sigma_tmpl ...
    3263             : !> \param nspins ...
    3264             : !> \param xalmo_history ...
    3265             : !> \param assume_t0_q0x ...
    3266             : !> \param optimize_theta ...
    3267             : !> \param envelope_amplitude ...
    3268             : !> \param eps_filter ...
    3269             : !> \param order_lanczos ...
    3270             : !> \param eps_lanczos ...
    3271             : !> \param max_iter_lanczos ...
    3272             : !> \param nocc_of_domain ...
    3273             : !> \par History
    3274             : !>       2016.11 created [Rustam Z Khaliullin]
    3275             : !> \author Rustam Z Khaliullin
    3276             : ! **************************************************************************************************
    3277         104 :    SUBROUTINE xalmo_initial_guess(m_guess, m_t_in, m_t0, m_quench_t, &
    3278         104 :                                   m_overlap, m_sigma_tmpl, nspins, xalmo_history, assume_t0_q0x, &
    3279             :                                   optimize_theta, envelope_amplitude, eps_filter, order_lanczos, eps_lanczos, &
    3280         104 :                                   max_iter_lanczos, nocc_of_domain)
    3281             : 
    3282             :       TYPE(dbcsr_type), DIMENSION(:), INTENT(INOUT)      :: m_guess
    3283             :       TYPE(dbcsr_type), DIMENSION(:), INTENT(IN)         :: m_t_in, m_t0, m_quench_t
    3284             :       TYPE(dbcsr_type), INTENT(IN)                       :: m_overlap
    3285             :       TYPE(dbcsr_type), DIMENSION(:), INTENT(IN)         :: m_sigma_tmpl
    3286             :       INTEGER, INTENT(IN)                                :: nspins
    3287             :       TYPE(almo_scf_history_type), INTENT(IN)            :: xalmo_history
    3288             :       LOGICAL, INTENT(IN)                                :: assume_t0_q0x, optimize_theta
    3289             :       REAL(KIND=dp), INTENT(IN)                          :: envelope_amplitude, eps_filter
    3290             :       INTEGER, INTENT(IN)                                :: order_lanczos
    3291             :       REAL(KIND=dp), INTENT(IN)                          :: eps_lanczos
    3292             :       INTEGER, INTENT(IN)                                :: max_iter_lanczos
    3293             :       INTEGER, DIMENSION(:, :), INTENT(IN)               :: nocc_of_domain
    3294             : 
    3295             :       CHARACTER(len=*), PARAMETER :: routineN = 'xalmo_initial_guess'
    3296             : 
    3297             :       INTEGER                                            :: handle, iaspc, ispin, istore, naspc, &
    3298             :                                                             unit_nr
    3299             :       LOGICAL                                            :: aspc_guess
    3300             :       REAL(KIND=dp)                                      :: alpha
    3301             :       TYPE(cp_logger_type), POINTER                      :: logger
    3302             :       TYPE(dbcsr_type)                                   :: m_extrapolated, m_sigma_tmp
    3303             : 
    3304         104 :       CALL timeset(routineN, handle)
    3305             : 
    3306             :       ! get a useful output_unit
    3307         104 :       logger => cp_get_default_logger()
    3308         104 :       IF (logger%para_env%is_source()) THEN
    3309          52 :          unit_nr = cp_logger_get_default_unit_nr(logger, local=.TRUE.)
    3310             :       ELSE
    3311             :          unit_nr = -1
    3312             :       END IF
    3313             : 
    3314         104 :       IF (optimize_theta) THEN
    3315           0 :          CPWARN("unused option")
    3316             :          ! just not to trigger unused variable
    3317           0 :          alpha = envelope_amplitude
    3318             :       END IF
    3319             : 
    3320             :       ! if extrapolation order is zero then the standard guess is used
    3321             :       ! ... the number of stored history points will remain zero if extrapolation order is zero
    3322         104 :       IF (xalmo_history%istore == 0) THEN
    3323             :          aspc_guess = .FALSE.
    3324             :       ELSE
    3325             :          aspc_guess = .TRUE.
    3326             :       END IF
    3327             : 
    3328             :       ! create initial guess
    3329             :       IF (.NOT. aspc_guess) THEN
    3330             : 
    3331         124 :          DO ispin = 1, nspins
    3332             : 
    3333             :             ! zero initial guess for the delocalization amplitudes
    3334             :             ! or the supplied guess for orbitals
    3335         124 :             IF (assume_t0_q0x) THEN
    3336          30 :                CALL dbcsr_set(m_guess(ispin), 0.0_dp)
    3337             :             ELSE
    3338             :                ! copy coefficients to m_guess
    3339          32 :                CALL dbcsr_copy(m_guess(ispin), m_t_in(ispin))
    3340             :             END IF
    3341             : 
    3342             :          END DO !ispins
    3343             : 
    3344             :       ELSE !aspc_guess
    3345             : 
    3346          42 :          CALL cite_reference(Kolafa2004)
    3347          42 :          CALL cite_reference(Kuhne2007)
    3348             : 
    3349          42 :          naspc = MIN(xalmo_history%istore, xalmo_history%nstore)
    3350          42 :          IF (unit_nr > 0) THEN
    3351             :             WRITE (unit_nr, FMT="(/,T2,A,/,/,T3,A,I0)") &
    3352          21 :                "Parameters for the always stable predictor-corrector (ASPC) method:", &
    3353          42 :                "ASPC order: ", naspc
    3354             :          END IF
    3355             : 
    3356          84 :          DO ispin = 1, nspins
    3357             : 
    3358             :             CALL dbcsr_create(m_extrapolated, &
    3359          42 :                               template=m_quench_t(ispin), matrix_type=dbcsr_type_no_symmetry)
    3360             :             CALL dbcsr_create(m_sigma_tmp, &
    3361          42 :                               template=m_sigma_tmpl(ispin), matrix_type=dbcsr_type_no_symmetry)
    3362             : 
    3363             :             ! set to zero before accumulation
    3364          42 :             CALL dbcsr_set(m_guess(ispin), 0.0_dp)
    3365             : 
    3366             :             ! extrapolation
    3367         124 :             DO iaspc = 1, naspc
    3368             : 
    3369          82 :                istore = MOD(xalmo_history%istore - iaspc, xalmo_history%nstore) + 1
    3370             :                alpha = (-1.0_dp)**(iaspc + 1)*REAL(iaspc, KIND=dp)* &
    3371          82 :                        binomial(2*naspc, naspc - iaspc)/binomial(2*naspc - 2, naspc - 1)
    3372          82 :                IF (unit_nr > 0) THEN
    3373             :                   WRITE (unit_nr, FMT="(T3,A2,I0,A4,F10.6)") &
    3374          41 :                      "B(", iaspc, ") = ", alpha
    3375             :                END IF
    3376             : 
    3377             :                ! m_extrapolated - initialize the correct sparsity pattern
    3378             :                ! it must be kept throughout extrapolation
    3379          82 :                CALL dbcsr_copy(m_extrapolated, m_quench_t(ispin))
    3380             : 
    3381             :                ! project t0 onto the previous DMs
    3382             :                ! note that t0 is projected instead of any other matrix (e.g.
    3383             :                ! t_SCF from the prev step or random t)
    3384             :                ! this is done to keep orbitals phase (i.e. sign) the same as in
    3385             :                ! t0. if this is not done then subtracting t0 on the next step
    3386             :                ! will produce a terrible guess and extrapolation will fail
    3387             :                CALL dbcsr_multiply("N", "N", 1.0_dp, &
    3388             :                                    xalmo_history%matrix_p_up_down(ispin, istore), &
    3389             :                                    m_t0(ispin), &
    3390             :                                    0.0_dp, m_extrapolated, &
    3391          82 :                                    retain_sparsity=.TRUE.)
    3392             :                ! normalize MOs
    3393             :                CALL orthogonalize_mos(ket=m_extrapolated, &
    3394             :                                       overlap=m_sigma_tmp, &
    3395             :                                       metric=m_overlap, &
    3396             :                                       retain_locality=.TRUE., &
    3397             :                                       only_normalize=.FALSE., &
    3398             :                                       nocc_of_domain=nocc_of_domain(:, ispin), &
    3399             :                                       eps_filter=eps_filter, &
    3400             :                                       order_lanczos=order_lanczos, &
    3401             :                                       eps_lanczos=eps_lanczos, &
    3402          82 :                                       max_iter_lanczos=max_iter_lanczos)
    3403             : 
    3404             :                ! now accumulate. correct sparsity is ensured
    3405             :                CALL dbcsr_add(m_guess(ispin), m_extrapolated, &
    3406         124 :                               1.0_dp, (1.0_dp*alpha)/naspc)
    3407             : 
    3408             :             END DO !iaspc
    3409             : 
    3410          42 :             CALL dbcsr_release(m_extrapolated)
    3411             : 
    3412             :             ! normalize MOs
    3413             :             CALL orthogonalize_mos(ket=m_guess(ispin), &
    3414             :                                    overlap=m_sigma_tmp, &
    3415             :                                    metric=m_overlap, &
    3416             :                                    retain_locality=.TRUE., &
    3417             :                                    only_normalize=.FALSE., &
    3418             :                                    nocc_of_domain=nocc_of_domain(:, ispin), &
    3419             :                                    eps_filter=eps_filter, &
    3420             :                                    order_lanczos=order_lanczos, &
    3421             :                                    eps_lanczos=eps_lanczos, &
    3422          42 :                                    max_iter_lanczos=max_iter_lanczos)
    3423             : 
    3424          42 :             CALL dbcsr_release(m_sigma_tmp)
    3425             : 
    3426             :             ! project the t0 space out from the extrapolated state
    3427             :             ! this can be done outside this subroutine
    3428          84 :             IF (assume_t0_q0x) THEN
    3429             :                CALL dbcsr_add(m_guess(ispin), m_t0(ispin), &
    3430          12 :                               1.0_dp, -1.0_dp)
    3431             :             END IF !assume_t0_q0x
    3432             : 
    3433             :          END DO !ispin
    3434             : 
    3435             :       END IF !aspc_guess?
    3436             : 
    3437         104 :       CALL timestop(handle)
    3438             : 
    3439         104 :    END SUBROUTINE xalmo_initial_guess
    3440             : 
    3441             : END MODULE almo_scf_methods
    3442             : 

Generated by: LCOV version 1.15