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

Generated by: LCOV version 1.15