LCOV - code coverage report
Current view: top level - src - qs_mo_methods.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:e08e82d) Lines: 90.8 % 369 335
Test Date: 2026-10-16 00:55:08 Functions: 92.3 % 13 12

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2026 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \brief collects routines that perform operations directly related to MOs
      10              : !> \note
      11              : !>      first version : most routines imported
      12              : !> \author Joost VandeVondele (2003-08)
      13              : ! **************************************************************************************************
      14              : MODULE qs_mo_methods
      15              :    USE admm_types,                      ONLY: admm_type
      16              :    USE admm_utils,                      ONLY: admm_correct_for_eigenvalues,&
      17              :                                               admm_uncorrect_for_eigenvalues
      18              :    USE cp_blacs_env,                    ONLY: cp_blacs_env_type
      19              :    USE cp_control_types,                ONLY: hairy_probes_type
      20              :    USE cp_dbcsr_api,                    ONLY: dbcsr_copy,&
      21              :                                               dbcsr_get_info,&
      22              :                                               dbcsr_init_p,&
      23              :                                               dbcsr_multiply,&
      24              :                                               dbcsr_p_type,&
      25              :                                               dbcsr_release_p,&
      26              :                                               dbcsr_type,&
      27              :                                               dbcsr_type_no_symmetry
      28              :    USE cp_dbcsr_diag,                   ONLY: cp_dbcsr_syevd,&
      29              :                                               cp_dbcsr_syevx
      30              :    USE cp_dbcsr_operations,             ONLY: copy_dbcsr_to_fm,&
      31              :                                               copy_fm_to_dbcsr,&
      32              :                                               cp_dbcsr_m_by_n_from_template,&
      33              :                                               cp_dbcsr_sm_fm_multiply
      34              :    USE cp_fm_basic_linalg,              ONLY: cp_fm_syrk,&
      35              :                                               cp_fm_triangular_multiply
      36              :    USE cp_fm_cholesky,                  ONLY: cp_fm_cholesky_decompose
      37              :    USE cp_fm_diag,                      ONLY: choose_eigv_solver,&
      38              :                                               cp_fm_power,&
      39              :                                               cp_fm_syevx
      40              :    USE cp_fm_struct,                    ONLY: cp_fm_struct_create,&
      41              :                                               cp_fm_struct_release,&
      42              :                                               cp_fm_struct_type
      43              :    USE cp_fm_types,                     ONLY: cp_fm_create,&
      44              :                                               cp_fm_get_info,&
      45              :                                               cp_fm_get_submatrix,&
      46              :                                               cp_fm_release,&
      47              :                                               cp_fm_set_all,&
      48              :                                               cp_fm_to_fm,&
      49              :                                               cp_fm_type
      50              :    USE cp_log_handling,                 ONLY: cp_logger_get_default_io_unit
      51              :    USE kinds,                           ONLY: dp
      52              :    USE message_passing,                 ONLY: mp_para_env_type
      53              :    USE parallel_gemm_api,               ONLY: parallel_gemm
      54              :    USE physcon,                         ONLY: evolt
      55              :    USE qs_mo_occupation,                ONLY: set_mo_occupation
      56              :    USE qs_mo_types,                     ONLY: get_mo_set,&
      57              :                                               mo_set_type
      58              :    USE scf_control_types,               ONLY: scf_control_type
      59              : #include "./base/base_uses.f90"
      60              : 
      61              :    IMPLICIT NONE
      62              :    PRIVATE
      63              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_mo_methods'
      64              : 
      65              :    PUBLIC :: make_basis_simple, make_basis_cholesky, make_basis_sv, make_basis_sm, &
      66              :              make_basis_lowdin, calculate_subspace_eigenvalues, &
      67              :              calculate_orthonormality, calculate_magnitude, make_mo_eig, &
      68              :              calculate_orbital_fock_elements, make_mo_set_canonical
      69              : 
      70              :    INTERFACE calculate_subspace_eigenvalues
      71              :       MODULE PROCEDURE subspace_eigenvalues_ks_fm
      72              :       MODULE PROCEDURE subspace_eigenvalues_ks_dbcsr
      73              :    END INTERFACE
      74              : 
      75              :    INTERFACE make_basis_sv
      76              :       MODULE PROCEDURE make_basis_sv_fm
      77              :       MODULE PROCEDURE make_basis_sv_dbcsr
      78              :    END INTERFACE
      79              : 
      80              : CONTAINS
      81              : 
      82              : ! **************************************************************************************************
      83              : !> \brief returns an S-orthonormal basis v (v^T S v ==1)
      84              : !> \param vmatrix ...
      85              : !> \param ncol ...
      86              : !> \param matrix_s ...
      87              : !> \par History
      88              : !>      03.2006 created [Joost VandeVondele]
      89              : ! **************************************************************************************************
      90        31456 :    SUBROUTINE make_basis_sm(vmatrix, ncol, matrix_s)
      91              :       TYPE(cp_fm_type), INTENT(IN)                       :: vmatrix
      92              :       INTEGER, INTENT(IN)                                :: ncol
      93              :       TYPE(dbcsr_type), POINTER                          :: matrix_s
      94              : 
      95              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'make_basis_sm'
      96              :       REAL(KIND=dp), PARAMETER                           :: rone = 1.0_dp, rzero = 0.0_dp
      97              : 
      98              :       INTEGER                                            :: handle, n, ncol_global
      99              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct_tmp
     100              :       TYPE(cp_fm_type)                                   :: overlap_vv, svmatrix
     101              : 
     102          304 :       IF (ncol == 0) RETURN
     103              : 
     104         7788 :       CALL timeset(routineN, handle)
     105              : 
     106         7788 :       CALL cp_fm_get_info(matrix=vmatrix, nrow_global=n, ncol_global=ncol_global)
     107         7788 :       IF (ncol > ncol_global) CPABORT("Wrong ncol value")
     108              : 
     109         7788 :       CALL cp_fm_create(svmatrix, vmatrix%matrix_struct, "SV", set_zero=.TRUE.)
     110         7788 :       CALL cp_dbcsr_sm_fm_multiply(matrix_s, vmatrix, svmatrix, ncol)
     111              : 
     112         7788 :       NULLIFY (fm_struct_tmp)
     113              :       CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=ncol, ncol_global=ncol, &
     114              :                                para_env=vmatrix%matrix_struct%para_env, &
     115         7788 :                                context=vmatrix%matrix_struct%context)
     116         7788 :       CALL cp_fm_create(overlap_vv, fm_struct_tmp, "overlap_vv")
     117         7788 :       CALL cp_fm_struct_release(fm_struct_tmp)
     118              : 
     119         7788 :       CALL parallel_gemm('T', 'N', ncol, ncol, n, rone, vmatrix, svmatrix, rzero, overlap_vv)
     120         7788 :       CALL cp_fm_cholesky_decompose(overlap_vv)
     121         7788 :       CALL cp_fm_triangular_multiply(overlap_vv, vmatrix, n_cols=ncol, side='R', invert_tr=.TRUE.)
     122              : 
     123         7788 :       CALL cp_fm_release(overlap_vv)
     124         7788 :       CALL cp_fm_release(svmatrix)
     125              : 
     126         7788 :       CALL timestop(handle)
     127              : 
     128         8092 :    END SUBROUTINE make_basis_sm
     129              : 
     130              : ! **************************************************************************************************
     131              : !> \brief returns an S-orthonormal basis v and the corresponding matrix S*v as well
     132              : !> \param vmatrix ...
     133              : !> \param ncol ...
     134              : !> \param svmatrix ...
     135              : !> \par History
     136              : !>      03.2006 created [Joost VandeVondele]
     137              : ! **************************************************************************************************
     138            0 :    SUBROUTINE make_basis_sv_fm(vmatrix, ncol, svmatrix)
     139              : 
     140              :       TYPE(cp_fm_type), INTENT(IN)                       :: vmatrix
     141              :       INTEGER, INTENT(IN)                                :: ncol
     142              :       TYPE(cp_fm_type), INTENT(IN)                       :: svmatrix
     143              : 
     144              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'make_basis_sv_fm'
     145              :       REAL(KIND=dp), PARAMETER                           :: rone = 1.0_dp, rzero = 0.0_dp
     146              : 
     147              :       INTEGER                                            :: handle, n, ncol_global
     148              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct_tmp
     149              :       TYPE(cp_fm_type)                                   :: overlap_vv
     150              : 
     151            0 :       IF (ncol == 0) RETURN
     152              : 
     153            0 :       CALL timeset(routineN, handle)
     154            0 :       NULLIFY (fm_struct_tmp)
     155              : 
     156            0 :       CALL cp_fm_get_info(matrix=vmatrix, nrow_global=n, ncol_global=ncol_global)
     157            0 :       IF (ncol > ncol_global) CPABORT("Wrong ncol value")
     158              : 
     159              :       CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=ncol, ncol_global=ncol, &
     160              :                                para_env=vmatrix%matrix_struct%para_env, &
     161            0 :                                context=vmatrix%matrix_struct%context)
     162            0 :       CALL cp_fm_create(overlap_vv, fm_struct_tmp, "overlap_vv")
     163            0 :       CALL cp_fm_struct_release(fm_struct_tmp)
     164              : 
     165            0 :       CALL parallel_gemm('T', 'N', ncol, ncol, n, rone, vmatrix, svmatrix, rzero, overlap_vv)
     166            0 :       CALL cp_fm_cholesky_decompose(overlap_vv)
     167            0 :       CALL cp_fm_triangular_multiply(overlap_vv, vmatrix, n_cols=ncol, side='R', invert_tr=.TRUE.)
     168            0 :       CALL cp_fm_triangular_multiply(overlap_vv, svmatrix, n_cols=ncol, side='R', invert_tr=.TRUE.)
     169              : 
     170            0 :       CALL cp_fm_release(overlap_vv)
     171              : 
     172            0 :       CALL timestop(handle)
     173              : 
     174            0 :    END SUBROUTINE make_basis_sv_fm
     175              : 
     176              : ! **************************************************************************************************
     177              : !> \brief ...
     178              : !> \param vmatrix ...
     179              : !> \param ncol ...
     180              : !> \param svmatrix ...
     181              : !> \param para_env ...
     182              : !> \param blacs_env ...
     183              : ! **************************************************************************************************
     184         3686 :    SUBROUTINE make_basis_sv_dbcsr(vmatrix, ncol, svmatrix, para_env, blacs_env)
     185              : 
     186              :       TYPE(dbcsr_type)                                   :: vmatrix
     187              :       INTEGER, INTENT(IN)                                :: ncol
     188              :       TYPE(dbcsr_type)                                   :: svmatrix
     189              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     190              :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env
     191              : 
     192              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'make_basis_sv_dbcsr'
     193              :       REAL(KIND=dp), PARAMETER                           :: rone = 1.0_dp, rzero = 0.0_dp
     194              : 
     195              :       INTEGER                                            :: handle, n, ncol_global
     196              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct_tmp
     197              :       TYPE(cp_fm_type)                                   :: fm_svmatrix, fm_vmatrix, overlap_vv
     198              : 
     199          122 :       IF (ncol == 0) RETURN
     200              : 
     201          594 :       CALL timeset(routineN, handle)
     202              : 
     203              :       !CALL cp_fm_get_info(matrix=vmatrix,nrow_global=n,ncol_global=ncol_global)
     204          594 :       CALL dbcsr_get_info(vmatrix, nfullrows_total=n, nfullcols_total=ncol_global)
     205          594 :       IF (ncol > ncol_global) CPABORT("Wrong ncol value")
     206              : 
     207              :       CALL cp_fm_struct_create(fm_struct_tmp, context=blacs_env, nrow_global=ncol, &
     208          594 :                                ncol_global=ncol, para_env=para_env)
     209          594 :       CALL cp_fm_create(overlap_vv, fm_struct_tmp, name="fm_overlap_vv")
     210          594 :       CALL cp_fm_struct_release(fm_struct_tmp)
     211              : 
     212              :       CALL cp_fm_struct_create(fm_struct_tmp, context=blacs_env, nrow_global=n, &
     213          594 :                                ncol_global=ncol_global, para_env=para_env)
     214          594 :       CALL cp_fm_create(fm_vmatrix, fm_struct_tmp, name="fm_vmatrix")
     215          594 :       CALL cp_fm_create(fm_svmatrix, fm_struct_tmp, name="fm_svmatrix")
     216          594 :       CALL cp_fm_struct_release(fm_struct_tmp)
     217              : 
     218          594 :       CALL copy_dbcsr_to_fm(vmatrix, fm_vmatrix)
     219          594 :       CALL copy_dbcsr_to_fm(svmatrix, fm_svmatrix)
     220              : 
     221          594 :       CALL parallel_gemm('T', 'N', ncol, ncol, n, rone, fm_vmatrix, fm_svmatrix, rzero, overlap_vv)
     222          594 :       CALL cp_fm_cholesky_decompose(overlap_vv)
     223          594 :       CALL cp_fm_triangular_multiply(overlap_vv, fm_vmatrix, n_cols=ncol, side='R', invert_tr=.TRUE.)
     224          594 :       CALL cp_fm_triangular_multiply(overlap_vv, fm_svmatrix, n_cols=ncol, side='R', invert_tr=.TRUE.)
     225              : 
     226          594 :       CALL copy_fm_to_dbcsr(fm_vmatrix, vmatrix)
     227          594 :       CALL copy_fm_to_dbcsr(fm_svmatrix, svmatrix)
     228              : 
     229          594 :       CALL cp_fm_release(overlap_vv)
     230          594 :       CALL cp_fm_release(fm_vmatrix)
     231          594 :       CALL cp_fm_release(fm_svmatrix)
     232              : 
     233          594 :       CALL timestop(handle)
     234              : 
     235          716 :    END SUBROUTINE make_basis_sv_dbcsr
     236              : 
     237              : ! **************************************************************************************************
     238              : !> \brief return a set of S orthonormal vectors (C^T S C == 1) where
     239              : !>      the cholesky decomposed form of S is passed as an argument
     240              : !> \param vmatrix ...
     241              : !> \param ncol ...
     242              : !> \param ortho cholesky decomposed S matrix
     243              : !> \par History
     244              : !>      03.2006 created [Joost VandeVondele]
     245              : !> \note
     246              : !>      if the cholesky decomposed S matrix is not available
     247              : !>      use make_basis_sm since this is much faster than computing the
     248              : !>      cholesky decomposition of S
     249              : ! **************************************************************************************************
     250        33012 :    SUBROUTINE make_basis_cholesky(vmatrix, ncol, ortho)
     251              : 
     252              :       TYPE(cp_fm_type), INTENT(IN)                       :: vmatrix
     253              :       INTEGER, INTENT(IN)                                :: ncol
     254              :       TYPE(cp_fm_type), INTENT(IN)                       :: ortho
     255              : 
     256              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'make_basis_cholesky'
     257              :       REAL(KIND=dp), PARAMETER                           :: rone = 1.0_dp, rzero = 0.0_dp
     258              : 
     259              :       INTEGER                                            :: handle, n, ncol_global
     260              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct_tmp
     261              :       TYPE(cp_fm_type)                                   :: overlap_vv
     262              : 
     263           84 :       IF (ncol == 0) RETURN
     264              : 
     265         8232 :       CALL timeset(routineN, handle)
     266         8232 :       NULLIFY (fm_struct_tmp)
     267              : 
     268         8232 :       CALL cp_fm_get_info(matrix=vmatrix, nrow_global=n, ncol_global=ncol_global)
     269         8232 :       IF (ncol > ncol_global) CPABORT("Wrong ncol value")
     270              : 
     271              :       CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=ncol, ncol_global=ncol, &
     272              :                                para_env=vmatrix%matrix_struct%para_env, &
     273         8232 :                                context=vmatrix%matrix_struct%context)
     274         8232 :       CALL cp_fm_create(overlap_vv, fm_struct_tmp, "overlap_vv")
     275         8232 :       CALL cp_fm_struct_release(fm_struct_tmp)
     276              : 
     277         8232 :       CALL cp_fm_triangular_multiply(ortho, vmatrix, n_cols=ncol)
     278         8232 :       CALL cp_fm_syrk('U', 'T', n, rone, vmatrix, 1, 1, rzero, overlap_vv)
     279         8232 :       CALL cp_fm_cholesky_decompose(overlap_vv)
     280         8232 :       CALL cp_fm_triangular_multiply(overlap_vv, vmatrix, n_cols=ncol, side='R', invert_tr=.TRUE.)
     281         8232 :       CALL cp_fm_triangular_multiply(ortho, vmatrix, n_cols=ncol, invert_tr=.TRUE.)
     282              : 
     283         8232 :       CALL cp_fm_release(overlap_vv)
     284              : 
     285         8232 :       CALL timestop(handle)
     286              : 
     287         8316 :    END SUBROUTINE make_basis_cholesky
     288              : 
     289              : ! **************************************************************************************************
     290              : !> \brief return a set of S orthonormal vectors (C^T S C == 1) where
     291              : !>      a Loedwin transformation is applied to keep the rotated vectors as close
     292              : !>      as possible to the original ones
     293              : !> \param vmatrix ...
     294              : !> \param ncol ...
     295              : !> \param matrix_s ...
     296              : !> \param
     297              : !> \par History
     298              : !>      05.2009 created [MI]
     299              : !> \note
     300              : ! **************************************************************************************************
     301        12540 :    SUBROUTINE make_basis_lowdin(vmatrix, ncol, matrix_s)
     302              : 
     303              :       TYPE(cp_fm_type), INTENT(IN)                       :: vmatrix
     304              :       INTEGER, INTENT(IN)                                :: ncol
     305              :       TYPE(dbcsr_type)                                   :: matrix_s
     306              : 
     307              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'make_basis_lowdin'
     308              :       REAL(KIND=dp), PARAMETER                           :: rone = 1.0_dp, rzero = 0.0_dp
     309              : 
     310              :       INTEGER                                            :: handle, n, ncol_global, ndep
     311              :       REAL(dp)                                           :: threshold
     312              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct_tmp
     313              :       TYPE(cp_fm_type)                                   :: csc, sc, work
     314              : 
     315            0 :       IF (ncol == 0) RETURN
     316              : 
     317         2090 :       CALL timeset(routineN, handle)
     318         2090 :       NULLIFY (fm_struct_tmp)
     319         2090 :       threshold = 1.0E-7_dp
     320         2090 :       CALL cp_fm_get_info(matrix=vmatrix, nrow_global=n, ncol_global=ncol_global)
     321         2090 :       IF (ncol > ncol_global) CPABORT("Wrong ncol value")
     322              : 
     323         2090 :       CALL cp_fm_create(sc, vmatrix%matrix_struct, "SC")
     324         2090 :       CALL cp_dbcsr_sm_fm_multiply(matrix_s, vmatrix, sc, ncol)
     325              : 
     326         2090 :       NULLIFY (fm_struct_tmp)
     327              :       CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=ncol, ncol_global=ncol, &
     328              :                                para_env=vmatrix%matrix_struct%para_env, &
     329         2090 :                                context=vmatrix%matrix_struct%context)
     330         2090 :       CALL cp_fm_create(csc, fm_struct_tmp, "csc")
     331         2090 :       CALL cp_fm_set_all(csc, 0.0_dp)
     332         2090 :       CALL cp_fm_create(work, fm_struct_tmp, "work")
     333         2090 :       CALL cp_fm_set_all(work, 0.0_dp)
     334         2090 :       CALL cp_fm_struct_release(fm_struct_tmp)
     335              : 
     336         2090 :       CALL parallel_gemm('T', 'N', ncol, ncol, n, rone, vmatrix, sc, rzero, csc)
     337         2090 :       CALL cp_fm_power(csc, work, -0.5_dp, threshold, ndep)
     338         2090 :       CALL parallel_gemm('N', 'N', n, ncol, ncol, rone, vmatrix, csc, rzero, sc)
     339         2090 :       CALL cp_fm_to_fm(sc, vmatrix, ncol, 1, 1)
     340              : 
     341         2090 :       CALL cp_fm_release(csc)
     342         2090 :       CALL cp_fm_release(sc)
     343         2090 :       CALL cp_fm_release(work)
     344              : 
     345         2090 :       CALL timestop(handle)
     346              : 
     347         2090 :    END SUBROUTINE make_basis_lowdin
     348              : 
     349              : ! **************************************************************************************************
     350              : !> \brief given a set of vectors, return an orthogonal (C^T C == 1) set
     351              : !>      spanning the same space (notice, only for cases where S==1)
     352              : !> \param vmatrix ...
     353              : !> \param ncol ...
     354              : !> \par History
     355              : !>      03.2006 created [Joost VandeVondele]
     356              : ! **************************************************************************************************
     357        14582 :    SUBROUTINE make_basis_simple(vmatrix, ncol)
     358              : 
     359              :       TYPE(cp_fm_type), INTENT(IN)                       :: vmatrix
     360              :       INTEGER, INTENT(IN)                                :: ncol
     361              : 
     362              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'make_basis_simple'
     363              :       REAL(KIND=dp), PARAMETER                           :: rone = 1.0_dp, rzero = 0.0_dp
     364              : 
     365              :       INTEGER                                            :: handle, n, ncol_global
     366              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct_tmp
     367              :       TYPE(cp_fm_type)                                   :: overlap_vv
     368              : 
     369           70 :       IF (ncol == 0) RETURN
     370              : 
     371         3628 :       CALL timeset(routineN, handle)
     372              : 
     373         3628 :       NULLIFY (fm_struct_tmp)
     374              : 
     375         3628 :       CALL cp_fm_get_info(matrix=vmatrix, nrow_global=n, ncol_global=ncol_global)
     376         3628 :       IF (ncol > ncol_global) CPABORT("Wrong ncol value")
     377              : 
     378              :       CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=ncol, ncol_global=ncol, &
     379              :                                para_env=vmatrix%matrix_struct%para_env, &
     380         3628 :                                context=vmatrix%matrix_struct%context)
     381         3628 :       CALL cp_fm_create(overlap_vv, fm_struct_tmp, "overlap_vv")
     382         3628 :       CALL cp_fm_struct_release(fm_struct_tmp)
     383              : 
     384         3628 :       CALL parallel_gemm('T', 'N', ncol, ncol, n, rone, vmatrix, vmatrix, rzero, overlap_vv)
     385         3628 :       CALL cp_fm_cholesky_decompose(overlap_vv)
     386         3628 :       CALL cp_fm_triangular_multiply(overlap_vv, vmatrix, n_cols=ncol, side='R', invert_tr=.TRUE.)
     387              : 
     388         3628 :       CALL cp_fm_release(overlap_vv)
     389              : 
     390         3628 :       CALL timestop(handle)
     391              : 
     392         3698 :    END SUBROUTINE make_basis_simple
     393              : 
     394              : ! **************************************************************************************************
     395              : !> \brief computes ritz values of a set of orbitals given a ks_matrix
     396              : !>      rotates the orbitals into eigenstates depending on do_rotation
     397              : !>      writes the evals to the screen depending on ionode/scr
     398              : !> \param orbitals S-orthonormal orbitals
     399              : !> \param ks_matrix Kohn-Sham matrix
     400              : !> \param evals_arg optional, filled with the evals
     401              : !> \param ionode , scr if present write to unit scr where ionode
     402              : !> \param scr ...
     403              : !> \param do_rotation optional rotate orbitals (default=.TRUE.)
     404              : !>        note that rotating the orbitals is slower
     405              : !> \param co_rotate an optional set of orbitals rotated by the same rotation matrix
     406              : !> \param co_rotate_dbcsr ...
     407              : !> \par History
     408              : !>      08.2004 documented and added do_rotation [Joost VandeVondele]
     409              : !>      09.2008 only compute eigenvalues if rotation is not needed
     410              : ! **************************************************************************************************
     411         8511 :    SUBROUTINE subspace_eigenvalues_ks_fm(orbitals, ks_matrix, evals_arg, ionode, scr, &
     412              :                                          do_rotation, co_rotate, co_rotate_dbcsr)
     413              : 
     414              :       TYPE(cp_fm_type), INTENT(IN)                       :: orbitals
     415              :       TYPE(dbcsr_type), POINTER                          :: ks_matrix
     416              :       REAL(KIND=dp), DIMENSION(:), OPTIONAL              :: evals_arg
     417              :       LOGICAL, INTENT(IN), OPTIONAL                      :: ionode
     418              :       INTEGER, INTENT(IN), OPTIONAL                      :: scr
     419              :       LOGICAL, INTENT(IN), OPTIONAL                      :: do_rotation
     420              :       TYPE(cp_fm_type), INTENT(IN), OPTIONAL             :: co_rotate
     421              :       TYPE(dbcsr_type), OPTIONAL, POINTER                :: co_rotate_dbcsr
     422              : 
     423              :       CHARACTER(len=*), PARAMETER :: routineN = 'subspace_eigenvalues_ks_fm'
     424              : 
     425              :       INTEGER                                            :: handle, i, j, n, ncol_global, nrow_global
     426              :       LOGICAL                                            :: compute_evecs, do_rotation_local
     427         8511 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: evals
     428              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct_tmp
     429              :       TYPE(cp_fm_type)                                   :: e_vectors, h_block, weighted_vectors, &
     430              :                                                             weighted_vectors2
     431              : 
     432         8511 :       CALL timeset(routineN, handle)
     433              : 
     434         8511 :       do_rotation_local = .TRUE.
     435         8511 :       IF (PRESENT(do_rotation)) do_rotation_local = do_rotation
     436              : 
     437         8511 :       NULLIFY (fm_struct_tmp)
     438              :       CALL cp_fm_get_info(matrix=orbitals, &
     439              :                           ncol_global=ncol_global, &
     440         8511 :                           nrow_global=nrow_global)
     441              : 
     442              :       IF (do_rotation_local) THEN
     443              :          compute_evecs = .TRUE.
     444              :       ELSE
     445              :          ! this would be the logical choice if syevx computing only evals were faster than syevd computing evecs and evals.
     446              :          compute_evecs = .FALSE.
     447              :          ! this is not the case, so lets compute evecs always
     448              :          compute_evecs = .TRUE.
     449              :       END IF
     450              : 
     451         8511 :       IF (ncol_global > 0) THEN
     452              : 
     453        25167 :          ALLOCATE (evals(ncol_global))
     454              : 
     455         8389 :          CALL cp_fm_create(weighted_vectors, orbitals%matrix_struct, "weighted_vectors")
     456              :          CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=ncol_global, ncol_global=ncol_global, &
     457              :                                   para_env=orbitals%matrix_struct%para_env, &
     458         8389 :                                   context=orbitals%matrix_struct%context)
     459         8389 :          CALL cp_fm_create(h_block, fm_struct_tmp, name="h block")
     460         8389 :          IF (compute_evecs) THEN
     461         8389 :             CALL cp_fm_create(e_vectors, fm_struct_tmp, name="e vectors")
     462              :          END IF
     463         8389 :          CALL cp_fm_struct_release(fm_struct_tmp)
     464              : 
     465              :          ! h subblock and diag
     466         8389 :          CALL cp_dbcsr_sm_fm_multiply(ks_matrix, orbitals, weighted_vectors, ncol_global)
     467              : 
     468              :          CALL parallel_gemm('T', 'N', ncol_global, ncol_global, nrow_global, 1.0_dp, &
     469         8389 :                             orbitals, weighted_vectors, 0.0_dp, h_block)
     470              : 
     471              :          ! if eigenvectors are required, go for syevd, otherwise only compute eigenvalues
     472              :          IF (compute_evecs) THEN
     473         8389 :             CALL choose_eigv_solver(h_block, e_vectors, evals)
     474              :          ELSE
     475              :             CALL cp_fm_syevx(h_block, eigenvalues=evals)
     476              :          END IF
     477              : 
     478              :          ! rotate the orbitals
     479         8389 :          IF (do_rotation_local) THEN
     480              :             CALL parallel_gemm('N', 'N', nrow_global, ncol_global, ncol_global, 1.0_dp, &
     481         8077 :                                orbitals, e_vectors, 0.0_dp, weighted_vectors)
     482         8077 :             CALL cp_fm_to_fm(weighted_vectors, orbitals)
     483         8077 :             IF (PRESENT(co_rotate)) THEN
     484              :                CALL parallel_gemm('N', 'N', nrow_global, ncol_global, ncol_global, 1.0_dp, &
     485           10 :                                   co_rotate, e_vectors, 0.0_dp, weighted_vectors)
     486           10 :                CALL cp_fm_to_fm(weighted_vectors, co_rotate)
     487              :             END IF
     488         8077 :             IF (PRESENT(co_rotate_dbcsr)) THEN
     489          362 :                IF (ASSOCIATED(co_rotate_dbcsr)) THEN
     490          358 :                   CALL cp_fm_create(weighted_vectors2, orbitals%matrix_struct, "weighted_vectors")
     491          358 :                   CALL copy_dbcsr_to_fm(co_rotate_dbcsr, weighted_vectors2)
     492              :                   CALL parallel_gemm('N', 'N', nrow_global, ncol_global, ncol_global, 1.0_dp, &
     493          358 :                                      weighted_vectors2, e_vectors, 0.0_dp, weighted_vectors)
     494          358 :                   CALL copy_fm_to_dbcsr(weighted_vectors, co_rotate_dbcsr)
     495          358 :                   CALL cp_fm_release(weighted_vectors2)
     496              :                END IF
     497              :             END IF
     498              :          END IF
     499              : 
     500              :          ! give output
     501         8389 :          IF (PRESENT(evals_arg)) THEN
     502         8357 :             n = MIN(SIZE(evals_arg), SIZE(evals))
     503        80199 :             evals_arg(1:n) = evals(1:n)
     504              :          END IF
     505              : 
     506         8389 :          IF (PRESENT(ionode) .OR. PRESENT(scr)) THEN
     507          182 :             IF (.NOT. PRESENT(ionode)) CPABORT("IONODE?")
     508          182 :             IF (.NOT. PRESENT(scr)) CPABORT("SCR?")
     509          182 :             IF (ionode) THEN
     510          228 :                DO i = 1, ncol_global, 4
     511          137 :                   j = MIN(3, ncol_global - i)
     512           91 :                   SELECT CASE (j)
     513              :                   CASE (3)
     514          105 :                      WRITE (scr, '(1X,4F16.8)') evals(i:i + j)
     515              :                   CASE (2)
     516            2 :                      WRITE (scr, '(1X,3F16.8)') evals(i:i + j)
     517              :                   CASE (1)
     518            7 :                      WRITE (scr, '(1X,2F16.8)') evals(i:i + j)
     519              :                   CASE (0)
     520          137 :                      WRITE (scr, '(1X,1F16.8)') evals(i:i + j)
     521              :                   END SELECT
     522              :                END DO
     523              :             END IF
     524              :          END IF
     525              : 
     526         8389 :          CALL cp_fm_release(weighted_vectors)
     527         8389 :          CALL cp_fm_release(h_block)
     528              :          IF (compute_evecs) THEN
     529         8389 :             CALL cp_fm_release(e_vectors)
     530              :          END IF
     531              : 
     532        25167 :          DEALLOCATE (evals)
     533              : 
     534              :       END IF
     535              : 
     536         8511 :       CALL timestop(handle)
     537              : 
     538        17022 :    END SUBROUTINE subspace_eigenvalues_ks_fm
     539              : 
     540              : ! **************************************************************************************************
     541              : !> \brief ...
     542              : !> \param orbitals ...
     543              : !> \param ks_matrix ...
     544              : !> \param evals_arg ...
     545              : !> \param ionode ...
     546              : !> \param scr ...
     547              : !> \param do_rotation ...
     548              : !> \param co_rotate ...
     549              : !> \param para_env ...
     550              : !> \param blacs_env ...
     551              : ! **************************************************************************************************
     552         6802 :    SUBROUTINE subspace_eigenvalues_ks_dbcsr(orbitals, ks_matrix, evals_arg, ionode, scr, &
     553              :                                             do_rotation, co_rotate, para_env, blacs_env)
     554              : 
     555              :       TYPE(dbcsr_type), POINTER                          :: orbitals, ks_matrix
     556              :       REAL(KIND=dp), DIMENSION(:), OPTIONAL              :: evals_arg
     557              :       LOGICAL, INTENT(IN), OPTIONAL                      :: ionode
     558              :       INTEGER, INTENT(IN), OPTIONAL                      :: scr
     559              :       LOGICAL, INTENT(IN), OPTIONAL                      :: do_rotation
     560              :       TYPE(dbcsr_type), OPTIONAL, POINTER                :: co_rotate
     561              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     562              :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env
     563              : 
     564              :       CHARACTER(len=*), PARAMETER :: routineN = 'subspace_eigenvalues_ks_dbcsr'
     565              : 
     566              :       INTEGER                                            :: handle, i, j, ncol_global, nrow_global
     567              :       LOGICAL                                            :: compute_evecs, do_rotation_local
     568         6802 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: evals
     569              :       TYPE(dbcsr_type), POINTER                          :: e_vectors, h_block, weighted_vectors
     570              : 
     571         6802 :       CALL timeset(routineN, handle)
     572              : 
     573         6802 :       do_rotation_local = .TRUE.
     574         6802 :       IF (PRESENT(do_rotation)) do_rotation_local = do_rotation
     575              : 
     576         6802 :       NULLIFY (e_vectors, h_block, weighted_vectors)
     577              : 
     578              :       CALL dbcsr_get_info(matrix=orbitals, &
     579              :                           nfullcols_total=ncol_global, &
     580         6802 :                           nfullrows_total=nrow_global)
     581              : 
     582              :       IF (do_rotation_local) THEN
     583              :          compute_evecs = .TRUE.
     584              :       ELSE
     585              :          ! this would be the logical choice if syevx computing only evals were faster than syevd computing evecs and evals.
     586              :          compute_evecs = .FALSE.
     587              :          ! this is not the case, so lets compute evecs always
     588              :          compute_evecs = .TRUE.
     589              :       END IF
     590              : 
     591         6802 :       IF (ncol_global > 0) THEN
     592              : 
     593        19746 :          ALLOCATE (evals(ncol_global))
     594              : 
     595         6582 :          CALL dbcsr_init_p(weighted_vectors)
     596         6582 :          CALL dbcsr_copy(weighted_vectors, orbitals, name="weighted_vectors")
     597              : 
     598         6582 :          CALL dbcsr_init_p(h_block)
     599              :          CALL cp_dbcsr_m_by_n_from_template(h_block, template=orbitals, m=ncol_global, n=ncol_global, &
     600         6582 :                                             sym=dbcsr_type_no_symmetry)
     601              : 
     602              : !!!!!!!!!!!!!!XXXXXXXXXXXXXXXXXXX!!!!!!!!!!!!!
     603              :          IF (compute_evecs) THEN
     604         6582 :             CALL dbcsr_init_p(e_vectors)
     605              :             CALL cp_dbcsr_m_by_n_from_template(e_vectors, template=orbitals, m=ncol_global, n=ncol_global, &
     606         6582 :                                                sym=dbcsr_type_no_symmetry)
     607              :          END IF
     608              : 
     609              :          ! h subblock and diag
     610              :          CALL dbcsr_multiply('N', 'N', 1.0_dp, ks_matrix, orbitals, &
     611         6582 :                              0.0_dp, weighted_vectors)
     612              :          !CALL cp_dbcsr_sm_fm_multiply(ks_matrix,orbitals,weighted_vectors, ncol_global)
     613              : 
     614         6582 :          CALL dbcsr_multiply('T', 'N', 1.0_dp, orbitals, weighted_vectors, 0.0_dp, h_block)
     615              :          !CALL parallel_gemm('T','N',ncol_global,ncol_global,nrow_global,1.0_dp, &
     616              :          !                orbitals,weighted_vectors,0.0_dp,h_block)
     617              : 
     618              :          ! if eigenvectors are required, go for syevd, otherwise only compute eigenvalues
     619              :          IF (compute_evecs) THEN
     620         6582 :             CALL cp_dbcsr_syevd(h_block, e_vectors, evals, para_env=para_env, blacs_env=blacs_env)
     621              :          ELSE
     622              :             CALL cp_dbcsr_syevx(h_block, eigenvalues=evals, para_env=para_env, blacs_env=blacs_env)
     623              :          END IF
     624              : 
     625              :          ! rotate the orbitals
     626         6582 :          IF (do_rotation_local) THEN
     627         3222 :             CALL dbcsr_multiply('N', 'N', 1.0_dp, orbitals, e_vectors, 0.0_dp, weighted_vectors)
     628              :             !CALL parallel_gemm('N','N',nrow_global,ncol_global,ncol_global,1.0_dp, &
     629              :             !             orbitals,e_vectors,0.0_dp,weighted_vectors)
     630         3222 :             CALL dbcsr_copy(orbitals, weighted_vectors)
     631              :             !CALL cp_fm_to_fm(weighted_vectors,orbitals)
     632         3222 :             IF (PRESENT(co_rotate)) THEN
     633         3202 :                IF (ASSOCIATED(co_rotate)) THEN
     634         3202 :                   CALL dbcsr_multiply('N', 'N', 1.0_dp, co_rotate, e_vectors, 0.0_dp, weighted_vectors)
     635              :                   !CALL parallel_gemm('N','N',nrow_global,ncol_global,ncol_global,1.0_dp, &
     636              :                   !     co_rotate,e_vectors,0.0_dp,weighted_vectors)
     637         3202 :                   CALL dbcsr_copy(co_rotate, weighted_vectors)
     638              :                   !CALL cp_fm_to_fm(weighted_vectors,co_rotate)
     639              :                END IF
     640              :             END IF
     641              :          END IF
     642              : 
     643              :          ! give output
     644         6582 :          IF (PRESENT(evals_arg)) THEN
     645        19944 :             evals_arg(:) = evals(:)
     646              :          END IF
     647              : 
     648         6582 :          IF (PRESENT(ionode) .OR. PRESENT(scr)) THEN
     649            0 :             IF (.NOT. PRESENT(ionode)) CPABORT("IONODE?")
     650            0 :             IF (.NOT. PRESENT(scr)) CPABORT("SCR?")
     651            0 :             IF (ionode) THEN
     652            0 :                DO i = 1, ncol_global, 4
     653            0 :                   j = MIN(3, ncol_global - i)
     654            0 :                   SELECT CASE (j)
     655              :                   CASE (3)
     656            0 :                      WRITE (scr, '(1X,4F16.8)') evals(i:i + j)
     657              :                   CASE (2)
     658            0 :                      WRITE (scr, '(1X,3F16.8)') evals(i:i + j)
     659              :                   CASE (1)
     660            0 :                      WRITE (scr, '(1X,2F16.8)') evals(i:i + j)
     661              :                   CASE (0)
     662            0 :                      WRITE (scr, '(1X,1F16.8)') evals(i:i + j)
     663              :                   END SELECT
     664              :                END DO
     665              :             END IF
     666              :          END IF
     667              : 
     668         6582 :          CALL dbcsr_release_p(weighted_vectors)
     669         6582 :          CALL dbcsr_release_p(h_block)
     670              :          IF (compute_evecs) THEN
     671         6582 :             CALL dbcsr_release_p(e_vectors)
     672              :          END IF
     673              : 
     674         6582 :          DEALLOCATE (evals)
     675              : 
     676              :       END IF
     677              : 
     678         6802 :       CALL timestop(handle)
     679              : 
     680         6802 :    END SUBROUTINE subspace_eigenvalues_ks_dbcsr
     681              : 
     682              : ! computes the effective orthonormality of a set of mos given an s-matrix
     683              : ! orthonormality is the max deviation from unity of the C^T S C
     684              : ! **************************************************************************************************
     685              : !> \brief ...
     686              : !> \param orthonormality ...
     687              : !> \param mo_array ...
     688              : !> \param matrix_s ...
     689              : ! **************************************************************************************************
     690         1196 :    SUBROUTINE calculate_orthonormality(orthonormality, mo_array, matrix_s)
     691              :       REAL(KIND=dp)                                      :: orthonormality
     692              :       TYPE(mo_set_type), DIMENSION(:), INTENT(IN)        :: mo_array
     693              :       TYPE(dbcsr_type), OPTIONAL, POINTER                :: matrix_s
     694              : 
     695              :       CHARACTER(len=*), PARAMETER :: routineN = 'calculate_orthonormality'
     696              : 
     697              :       INTEGER                                            :: handle, i, ispin, j, k, n, ncol_local, &
     698              :                                                             nrow_local, nspin
     699         1196 :       INTEGER, DIMENSION(:), POINTER                     :: col_indices, row_indices
     700              :       REAL(KIND=dp)                                      :: alpha, max_alpha
     701              :       TYPE(cp_fm_struct_type), POINTER                   :: tmp_fm_struct
     702              :       TYPE(cp_fm_type)                                   :: overlap, svec
     703              : 
     704         1196 :       NULLIFY (tmp_fm_struct)
     705              : 
     706         1196 :       CALL timeset(routineN, handle)
     707              : 
     708         1196 :       nspin = SIZE(mo_array)
     709         1196 :       max_alpha = 0.0_dp
     710              : 
     711         2404 :       DO ispin = 1, nspin
     712         1208 :          IF (PRESENT(matrix_s)) THEN
     713              :             ! get S*C
     714         1150 :             CALL cp_fm_create(svec, mo_array(ispin)%mo_coeff%matrix_struct)
     715              :             CALL cp_fm_get_info(mo_array(ispin)%mo_coeff, &
     716         1150 :                                 nrow_global=n, ncol_global=k)
     717              :             CALL cp_dbcsr_sm_fm_multiply(matrix_s, mo_array(ispin)%mo_coeff, &
     718         1150 :                                          svec, k)
     719              :             ! get C^T (S*C)
     720              :             CALL cp_fm_struct_create(tmp_fm_struct, nrow_global=k, ncol_global=k, &
     721              :                                      para_env=mo_array(ispin)%mo_coeff%matrix_struct%para_env, &
     722         1150 :                                      context=mo_array(ispin)%mo_coeff%matrix_struct%context)
     723         1150 :             CALL cp_fm_create(overlap, tmp_fm_struct)
     724         1150 :             CALL cp_fm_struct_release(tmp_fm_struct)
     725              :             CALL parallel_gemm('T', 'N', k, k, n, 1.0_dp, mo_array(ispin)%mo_coeff, &
     726         1150 :                                svec, 0.0_dp, overlap)
     727         1150 :             CALL cp_fm_release(svec)
     728              :          ELSE
     729              :             ! orthogonal basis C^T C
     730              :             CALL cp_fm_get_info(mo_array(ispin)%mo_coeff, &
     731           58 :                                 nrow_global=n, ncol_global=k)
     732              :             CALL cp_fm_struct_create(tmp_fm_struct, nrow_global=k, ncol_global=k, &
     733              :                                      para_env=mo_array(ispin)%mo_coeff%matrix_struct%para_env, &
     734           58 :                                      context=mo_array(ispin)%mo_coeff%matrix_struct%context)
     735           58 :             CALL cp_fm_create(overlap, tmp_fm_struct)
     736           58 :             CALL cp_fm_struct_release(tmp_fm_struct)
     737              :             CALL parallel_gemm('T', 'N', k, k, n, 1.0_dp, mo_array(ispin)%mo_coeff, &
     738           58 :                                mo_array(ispin)%mo_coeff, 0.0_dp, overlap)
     739              :          END IF
     740              :          CALL cp_fm_get_info(overlap, nrow_local=nrow_local, ncol_local=ncol_local, &
     741         1208 :                              row_indices=row_indices, col_indices=col_indices)
     742         8305 :          DO i = 1, nrow_local
     743       425678 :             DO j = 1, ncol_local
     744       417373 :                alpha = overlap%local_data(i, j)
     745       417373 :                IF (row_indices(i) == col_indices(j)) alpha = alpha - 1.0_dp
     746       424470 :                max_alpha = MAX(max_alpha, ABS(alpha))
     747              :             END DO
     748              :          END DO
     749         3612 :          CALL cp_fm_release(overlap)
     750              :       END DO
     751         1196 :       CALL mo_array(1)%mo_coeff%matrix_struct%para_env%max(max_alpha)
     752         1196 :       orthonormality = max_alpha
     753              :       ! write(*,*) "max deviation from orthonormalization ",orthonormality
     754              : 
     755         1196 :       CALL timestop(handle)
     756              : 
     757         1196 :    END SUBROUTINE calculate_orthonormality
     758              : 
     759              : ! computes the minimum/maximum magnitudes of C^T C. This could be useful
     760              : ! to detect problems in the case of nearly singular overlap matrices.
     761              : ! in this case, we expect the ratio of min/max to be large
     762              : ! this routine is only similar to mo_orthonormality if S==1
     763              : ! **************************************************************************************************
     764              : !> \brief ...
     765              : !> \param mo_array ...
     766              : !> \param mo_mag_min ...
     767              : !> \param mo_mag_max ...
     768              : ! **************************************************************************************************
     769         1176 :    SUBROUTINE calculate_magnitude(mo_array, mo_mag_min, mo_mag_max)
     770              :       TYPE(mo_set_type), DIMENSION(:), INTENT(IN)        :: mo_array
     771              :       REAL(KIND=dp)                                      :: mo_mag_min, mo_mag_max
     772              : 
     773              :       CHARACTER(len=*), PARAMETER :: routineN = 'calculate_magnitude'
     774              : 
     775              :       INTEGER                                            :: handle, ispin, k, n, nspin
     776         1176 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: evals
     777              :       TYPE(cp_fm_struct_type), POINTER                   :: tmp_fm_struct
     778              :       TYPE(cp_fm_type)                                   :: evecs, overlap
     779              : 
     780         1176 :       NULLIFY (tmp_fm_struct)
     781              : 
     782         1176 :       CALL timeset(routineN, handle)
     783              : 
     784         1176 :       nspin = SIZE(mo_array)
     785         1176 :       mo_mag_min = HUGE(0.0_dp)
     786         1176 :       mo_mag_max = -HUGE(0.0_dp)
     787         2352 :       DO ispin = 1, nspin
     788              :          CALL cp_fm_get_info(mo_array(ispin)%mo_coeff, &
     789         1176 :                              nrow_global=n, ncol_global=k)
     790         3528 :          ALLOCATE (evals(k))
     791              :          CALL cp_fm_struct_create(tmp_fm_struct, nrow_global=k, ncol_global=k, &
     792              :                                   para_env=mo_array(ispin)%mo_coeff%matrix_struct%para_env, &
     793         1176 :                                   context=mo_array(ispin)%mo_coeff%matrix_struct%context)
     794         1176 :          CALL cp_fm_create(overlap, tmp_fm_struct)
     795         1176 :          CALL cp_fm_create(evecs, tmp_fm_struct)
     796         1176 :          CALL cp_fm_struct_release(tmp_fm_struct)
     797              :          CALL parallel_gemm('T', 'N', k, k, n, 1.0_dp, mo_array(ispin)%mo_coeff, &
     798         1176 :                             mo_array(ispin)%mo_coeff, 0.0_dp, overlap)
     799         1176 :          CALL choose_eigv_solver(overlap, evecs, evals)
     800        15238 :          mo_mag_min = MIN(MINVAL(evals), mo_mag_min)
     801        15238 :          mo_mag_max = MAX(MAXVAL(evals), mo_mag_max)
     802         1176 :          CALL cp_fm_release(overlap)
     803         1176 :          CALL cp_fm_release(evecs)
     804         4704 :          DEALLOCATE (evals)
     805              :       END DO
     806         1176 :       CALL timestop(handle)
     807              : 
     808         2352 :    END SUBROUTINE calculate_magnitude
     809              : 
     810              : ! **************************************************************************************************
     811              : !> \brief  Calculate KS eigenvalues starting from  OF MOS
     812              : !> \param mos ...
     813              : !> \param nspins ...
     814              : !> \param ks_rmpv ...
     815              : !> \param scf_control ...
     816              : !> \param mo_derivs ...
     817              : !> \param admm_env ...
     818              : !> \param hairy_probes ...
     819              : !> \param probe ...
     820              : !> \par History
     821              : !>         02.2013 moved from qs_scf_post_gpw
     822              : !>
     823              : ! **************************************************************************************************
     824          204 :    SUBROUTINE make_mo_eig(mos, nspins, ks_rmpv, scf_control, mo_derivs, admm_env, &
     825              :                           hairy_probes, probe)
     826              : 
     827              :       TYPE(mo_set_type), DIMENSION(:), INTENT(INOUT)     :: mos
     828              :       INTEGER, INTENT(IN)                                :: nspins
     829              :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: ks_rmpv
     830              :       TYPE(scf_control_type), POINTER                    :: scf_control
     831              :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: mo_derivs
     832              :       TYPE(admm_type), OPTIONAL, POINTER                 :: admm_env
     833              :       LOGICAL, OPTIONAL                                  :: hairy_probes
     834              :       TYPE(hairy_probes_type), DIMENSION(:), OPTIONAL, &
     835              :          POINTER                                         :: probe
     836              : 
     837              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'make_mo_eig'
     838              : 
     839              :       INTEGER                                            :: handle, homo, ispin, nmo, output_unit
     840          204 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: mo_eigenvalues
     841              :       TYPE(cp_fm_type), POINTER                          :: mo_coeff
     842              :       TYPE(dbcsr_type), POINTER                          :: mo_coeff_deriv
     843              : 
     844          204 :       CALL timeset(routineN, handle)
     845              : 
     846          204 :       NULLIFY (mo_coeff_deriv, mo_coeff, mo_eigenvalues)
     847          204 :       output_unit = cp_logger_get_default_io_unit()
     848              : 
     849          448 :       DO ispin = 1, nspins
     850              :          CALL get_mo_set(mo_set=mos(ispin), mo_coeff=mo_coeff, &
     851          244 :                          eigenvalues=mo_eigenvalues, homo=homo, nmo=nmo)
     852          244 :          IF (output_unit > 0) WRITE (output_unit, *) " "
     853          244 :          IF (output_unit > 0) WRITE (output_unit, *) " Eigenvalues of the occupied subspace spin ", ispin
     854              :          !      IF (homo /= nmo) THEN
     855              :          !         IF (output_unit>0) WRITE(output_unit,*)" and ",nmo-homo," added MO eigenvalues"
     856              :          !      END IF
     857          244 :          IF (output_unit > 0) WRITE (output_unit, *) "---------------------------------------------"
     858              : 
     859          244 :          IF (scf_control%use_ot) THEN
     860              :             ! Also rotate the OT derivs, since they are needed for force calculations
     861          128 :             IF (ASSOCIATED(mo_derivs)) THEN
     862          128 :                mo_coeff_deriv => mo_derivs(ispin)%matrix
     863              :             ELSE
     864            0 :                mo_coeff_deriv => NULL()
     865              :             END IF
     866              : 
     867              :             ! If we do ADMM, we add have to modify the Kohn-Sham matrix
     868          128 :             IF (PRESENT(admm_env)) THEN
     869            0 :                CALL admm_correct_for_eigenvalues(ispin, admm_env, ks_rmpv(ispin)%matrix)
     870              :             END IF
     871              : 
     872              :             CALL calculate_subspace_eigenvalues(mo_coeff, ks_rmpv(ispin)%matrix, mo_eigenvalues, &
     873              :                                                 scr=output_unit, ionode=output_unit > 0, do_rotation=.TRUE., &
     874          128 :                                                 co_rotate_dbcsr=mo_coeff_deriv)
     875              : 
     876              :             ! If we do ADMM, we restore the original Kohn-Sham matrix
     877          128 :             IF (PRESENT(admm_env)) THEN
     878            0 :                CALL admm_uncorrect_for_eigenvalues(ispin, admm_env, ks_rmpv(ispin)%matrix)
     879              :             END IF
     880              :          ELSE
     881          567 :             IF (output_unit > 0) WRITE (output_unit, '(4(1X,1F16.8))') mo_eigenvalues(1:homo)
     882              :          END IF
     883          244 :          IF (.NOT. scf_control%diagonalization%mom) THEN
     884          244 :             IF (PRESENT(hairy_probes) .EQV. .TRUE.) THEN
     885            0 :                scf_control%smear%do_smear = .FALSE.
     886              :                CALL set_mo_occupation(mo_set=mos(ispin), &
     887              :                                       smear=scf_control%smear, &
     888            0 :                                       probe=probe)
     889              :             ELSE
     890          244 :                CALL set_mo_occupation(mo_set=mos(ispin), smear=scf_control%smear)
     891              :             END IF
     892              :          END IF
     893          244 :          IF (output_unit > 0) WRITE (output_unit, '(T2,A,F12.6)') &
     894          570 :             "Fermi Energy [eV] :", mos(ispin)%mu*evolt
     895              :       END DO
     896              : 
     897          204 :       CALL timestop(handle)
     898              : 
     899          204 :    END SUBROUTINE make_mo_eig
     900              : 
     901              : ! **************************************************************************************************
     902              : !> \brief Orbital energies <phi_i|F|phi_i> of a set of orbitals and the largest off-diagonal Fock
     903              : !>        matrix element max_{i/=j} |<phi_i|F|phi_j>| within the set. Unlike
     904              : !>        calculate_subspace_eigenvalues, the orbitals are not rotated and the energies belong to
     905              : !>        the given orbitals. The orbitals are canonical if the off-diagonal elements vanish.
     906              : !> \param orbitals S-orthonormal orbitals (columns)
     907              : !> \param ks_matrix Kohn-Sham or Fock matrix
     908              : !> \param orbital_energies diagonal elements; filled up to MIN(SIZE, number of orbitals)
     909              : !> \param max_offdiag largest off-diagonal element in absolute value
     910              : ! **************************************************************************************************
     911          252 :    SUBROUTINE calculate_orbital_fock_elements(orbitals, ks_matrix, orbital_energies, max_offdiag)
     912              :       TYPE(cp_fm_type), INTENT(IN)                       :: orbitals
     913              :       TYPE(dbcsr_type), POINTER                          :: ks_matrix
     914              :       REAL(KIND=dp), DIMENSION(:), INTENT(OUT)           :: orbital_energies
     915              :       REAL(KIND=dp), INTENT(OUT)                         :: max_offdiag
     916              : 
     917              :       CHARACTER(len=*), PARAMETER :: routineN = 'calculate_orbital_fock_elements'
     918              : 
     919              :       INTEGER                                            :: handle, i, ncol_global, nrow_global
     920          252 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: fock
     921              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct_tmp
     922              :       TYPE(cp_fm_type)                                   :: h_block, weighted_vectors
     923              : 
     924          252 :       CALL timeset(routineN, handle)
     925              : 
     926         1496 :       orbital_energies = 0.0_dp
     927          252 :       max_offdiag = 0.0_dp
     928          252 :       CALL cp_fm_get_info(matrix=orbitals, ncol_global=ncol_global, nrow_global=nrow_global)
     929          252 :       IF (ncol_global > 0) THEN
     930          252 :          NULLIFY (fm_struct_tmp)
     931          252 :          CALL cp_fm_create(weighted_vectors, orbitals%matrix_struct, "weighted_vectors")
     932              :          CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=ncol_global, ncol_global=ncol_global, &
     933              :                                   para_env=orbitals%matrix_struct%para_env, &
     934          252 :                                   context=orbitals%matrix_struct%context)
     935          252 :          CALL cp_fm_create(h_block, fm_struct_tmp, name="h block")
     936          252 :          CALL cp_fm_struct_release(fm_struct_tmp)
     937              : 
     938          252 :          CALL cp_dbcsr_sm_fm_multiply(ks_matrix, orbitals, weighted_vectors, ncol_global)
     939              :          CALL parallel_gemm('T', 'N', ncol_global, ncol_global, nrow_global, 1.0_dp, &
     940          252 :                             orbitals, weighted_vectors, 0.0_dp, h_block)
     941              : 
     942         1008 :          ALLOCATE (fock(ncol_global, ncol_global))
     943          252 :          CALL cp_fm_get_submatrix(h_block, fock)
     944         1480 :          DO i = 1, MIN(ncol_global, SIZE(orbital_energies))
     945         1480 :             orbital_energies(i) = fock(i, i)
     946              :          END DO
     947         1824 :          DO i = 1, ncol_global
     948         1824 :             fock(i, i) = 0.0_dp
     949              :          END DO
     950        16892 :          max_offdiag = MAXVAL(ABS(fock))
     951          252 :          DEALLOCATE (fock)
     952              : 
     953          252 :          CALL cp_fm_release(weighted_vectors)
     954          756 :          CALL cp_fm_release(h_block)
     955              :       END IF
     956              : 
     957          252 :       CALL timestop(handle)
     958              : 
     959          504 :    END SUBROUTINE calculate_orbital_fock_elements
     960              : 
     961              : ! **************************************************************************************************
     962              : !> \brief Rotates the orbitals of an MO set into canonical orbitals (eigenvectors of the Fock
     963              : !>        matrix in the space of the orbitals), separately within the occupied and within the
     964              : !>        unoccupied orbitals, so that the occupied space (the determinant) is unchanged.
     965              : !>        The orbitals are rotated in place: the eigenvalues, the DBCSR copy of the coefficients
     966              : !>        (if used) and the orbital derivatives (if given) are rotated consistently, C' = C U and
     967              : !>        D' = D U. Nothing is done if the orbitals are already canonical, i.e. if no
     968              : !>        off-diagonal Fock matrix element exceeds eps_canonical; orbitals of a converged
     969              : !>        diagonalization SCF are therefore never changed.
     970              : !>        Requires integer occupations (0 or the maximum occupation); fractionally occupied
     971              : !>        orbitals and ROKS orbitals must not be mixed this way.
     972              : !> \param mo_set the MO set (e.g. the SCF orbitals after an OT optimization)
     973              : !> \param ks_matrix Kohn-Sham or Fock matrix
     974              : !> \param eps_canonical largest off-diagonal Fock matrix element accepted as canonical
     975              : !> \param rotated whether the orbitals were rotated
     976              : !> \param max_offdiag largest off-diagonal Fock matrix element before the rotation
     977              : !> \param mo_derivs derivatives of the energy with respect to the orbitals (OT), rotated as well
     978              : ! **************************************************************************************************
     979           10 :    SUBROUTINE make_mo_set_canonical(mo_set, ks_matrix, eps_canonical, rotated, max_offdiag, mo_derivs)
     980              :       TYPE(mo_set_type), INTENT(INOUT)                   :: mo_set
     981              :       TYPE(dbcsr_type), POINTER                          :: ks_matrix
     982              :       REAL(KIND=dp), INTENT(IN)                          :: eps_canonical
     983              :       LOGICAL, INTENT(OUT)                               :: rotated
     984              :       REAL(KIND=dp), INTENT(OUT)                         :: max_offdiag
     985              :       TYPE(dbcsr_type), OPTIONAL, POINTER                :: mo_derivs
     986              : 
     987              :       CHARACTER(len=*), PARAMETER :: routineN = 'make_mo_set_canonical'
     988              :       REAL(KIND=dp), PARAMETER                           :: eps_occ = 1.0E-10_dp
     989              : 
     990              :       INTEGER                                            :: first, handle, i, iblock, n, nmo, nocc, &
     991              :                                                             nrow_global
     992              :       LOGICAL                                            :: do_derivs
     993              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: energies
     994              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct_tmp
     995              :       TYPE(cp_fm_type)                                   :: block_coeff, block_derivs, derivs
     996              : 
     997           10 :       CALL timeset(routineN, handle)
     998              : 
     999           10 :       rotated = .FALSE.
    1000           10 :       nmo = mo_set%nmo
    1001           10 :       IF (mo_set%use_mo_coeff_b) CALL copy_dbcsr_to_fm(mo_set%mo_coeff_b, mo_set%mo_coeff)
    1002           30 :       ALLOCATE (energies(nmo))
    1003           10 :       CALL calculate_orbital_fock_elements(mo_set%mo_coeff, ks_matrix, energies, max_offdiag)
    1004           10 :       DEALLOCATE (energies)
    1005              : 
    1006           10 :       IF (max_offdiag > eps_canonical) THEN
    1007           50 :          DO i = 1, nmo
    1008           40 :             IF (ABS(mo_set%occupation_numbers(i)) > eps_occ .AND. &
    1009           10 :                 ABS(mo_set%occupation_numbers(i) - mo_set%maxocc) > eps_occ) THEN
    1010            0 :                CPABORT("Canonicalization of orbitals with fractional occupations is not possible")
    1011              :             END IF
    1012              :          END DO
    1013           10 :          do_derivs = .FALSE.
    1014           10 :          IF (PRESENT(mo_derivs)) do_derivs = ASSOCIATED(mo_derivs)
    1015              :          ! occupied orbitals: those with nonzero occupation, they come first
    1016           50 :          nocc = COUNT(mo_set%occupation_numbers(1:nmo) > eps_occ)
    1017           10 :          CALL cp_fm_get_info(matrix=mo_set%mo_coeff, nrow_global=nrow_global)
    1018           10 :          IF (do_derivs) THEN
    1019           10 :             CALL cp_fm_create(derivs, mo_set%mo_coeff%matrix_struct, name="orbital derivatives")
    1020           10 :             CALL copy_dbcsr_to_fm(mo_derivs, derivs)
    1021              :          END IF
    1022           30 :          DO iblock = 1, 2
    1023           20 :             IF (iblock == 1) THEN
    1024           10 :                first = 1
    1025           10 :                n = nocc
    1026              :             ELSE
    1027           10 :                first = nocc + 1
    1028           10 :                n = nmo - nocc
    1029              :             END IF
    1030           20 :             IF (n <= 0) CYCLE
    1031           10 :             NULLIFY (fm_struct_tmp)
    1032              :             CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nrow_global, ncol_global=n, &
    1033           10 :                                      template_fmstruct=mo_set%mo_coeff%matrix_struct)
    1034           10 :             CALL cp_fm_create(block_coeff, fm_struct_tmp, name="canonicalized orbitals")
    1035           10 :             CALL cp_fm_to_fm(mo_set%mo_coeff, block_coeff, n, first, 1)
    1036           10 :             IF (do_derivs) THEN
    1037           10 :                CALL cp_fm_create(block_derivs, fm_struct_tmp, name="rotated orbital derivatives")
    1038           10 :                CALL cp_fm_to_fm(derivs, block_derivs, n, first, 1)
    1039              :                CALL calculate_subspace_eigenvalues(block_coeff, ks_matrix, &
    1040              :                                                    evals_arg=mo_set%eigenvalues(first:first + n - 1), &
    1041           10 :                                                    do_rotation=.TRUE., co_rotate=block_derivs)
    1042           10 :                CALL cp_fm_to_fm(block_derivs, derivs, n, 1, first)
    1043           10 :                CALL cp_fm_release(block_derivs)
    1044              :             ELSE
    1045              :                CALL calculate_subspace_eigenvalues(block_coeff, ks_matrix, &
    1046              :                                                    evals_arg=mo_set%eigenvalues(first:first + n - 1), &
    1047            0 :                                                    do_rotation=.TRUE.)
    1048              :             END IF
    1049           10 :             CALL cp_fm_struct_release(fm_struct_tmp)
    1050           10 :             CALL cp_fm_to_fm(block_coeff, mo_set%mo_coeff, n, 1, first)
    1051           40 :             CALL cp_fm_release(block_coeff)
    1052              :          END DO
    1053           10 :          IF (do_derivs) THEN
    1054           10 :             CALL copy_fm_to_dbcsr(derivs, mo_derivs)
    1055           10 :             CALL cp_fm_release(derivs)
    1056              :          END IF
    1057           10 :          IF (mo_set%use_mo_coeff_b) CALL copy_fm_to_dbcsr(mo_set%mo_coeff, mo_set%mo_coeff_b)
    1058           10 :          rotated = .TRUE.
    1059              :       END IF
    1060              : 
    1061           10 :       CALL timestop(handle)
    1062              : 
    1063           20 :    END SUBROUTINE make_mo_set_canonical
    1064              : 
    1065              : END MODULE qs_mo_methods
        

Generated by: LCOV version 2.0-1