LCOV - code coverage report
Current view: top level - src - qs_mo_methods.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:cb5d5fc) Lines: 88.5 % 295 261
Test Date: 2026-04-24 07:01:27 Functions: 90.9 % 11 10

            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_release,&
      46              :                                               cp_fm_set_all,&
      47              :                                               cp_fm_to_fm,&
      48              :                                               cp_fm_type
      49              :    USE cp_log_handling,                 ONLY: cp_logger_get_default_io_unit
      50              :    USE kinds,                           ONLY: dp
      51              :    USE message_passing,                 ONLY: mp_para_env_type
      52              :    USE parallel_gemm_api,               ONLY: parallel_gemm
      53              :    USE physcon,                         ONLY: evolt
      54              :    USE qs_mo_occupation,                ONLY: set_mo_occupation
      55              :    USE qs_mo_types,                     ONLY: get_mo_set,&
      56              :                                               mo_set_type
      57              :    USE scf_control_types,               ONLY: scf_control_type
      58              : #include "./base/base_uses.f90"
      59              : 
      60              :    IMPLICIT NONE
      61              :    PRIVATE
      62              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_mo_methods'
      63              : 
      64              :    PUBLIC :: make_basis_simple, make_basis_cholesky, make_basis_sv, make_basis_sm, &
      65              :              make_basis_lowdin, calculate_subspace_eigenvalues, &
      66              :              calculate_orthonormality, calculate_magnitude, make_mo_eig
      67              : 
      68              :    INTERFACE calculate_subspace_eigenvalues
      69              :       MODULE PROCEDURE subspace_eigenvalues_ks_fm
      70              :       MODULE PROCEDURE subspace_eigenvalues_ks_dbcsr
      71              :    END INTERFACE
      72              : 
      73              :    INTERFACE make_basis_sv
      74              :       MODULE PROCEDURE make_basis_sv_fm
      75              :       MODULE PROCEDURE make_basis_sv_dbcsr
      76              :    END INTERFACE
      77              : 
      78              : CONTAINS
      79              : 
      80              : ! **************************************************************************************************
      81              : !> \brief returns an S-orthonormal basis v (v^T S v ==1)
      82              : !> \param vmatrix ...
      83              : !> \param ncol ...
      84              : !> \param matrix_s ...
      85              : !> \par History
      86              : !>      03.2006 created [Joost VandeVondele]
      87              : ! **************************************************************************************************
      88        29056 :    SUBROUTINE make_basis_sm(vmatrix, ncol, matrix_s)
      89              :       TYPE(cp_fm_type), INTENT(IN)                       :: vmatrix
      90              :       INTEGER, INTENT(IN)                                :: ncol
      91              :       TYPE(dbcsr_type), POINTER                          :: matrix_s
      92              : 
      93              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'make_basis_sm'
      94              :       REAL(KIND=dp), PARAMETER                           :: rone = 1.0_dp, rzero = 0.0_dp
      95              : 
      96              :       INTEGER                                            :: handle, n, ncol_global
      97              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct_tmp
      98              :       TYPE(cp_fm_type)                                   :: overlap_vv, svmatrix
      99              : 
     100          128 :       IF (ncol == 0) RETURN
     101              : 
     102         7232 :       CALL timeset(routineN, handle)
     103              : 
     104         7232 :       CALL cp_fm_get_info(matrix=vmatrix, nrow_global=n, ncol_global=ncol_global)
     105         7232 :       IF (ncol > ncol_global) CPABORT("Wrong ncol value")
     106              : 
     107         7232 :       CALL cp_fm_create(svmatrix, vmatrix%matrix_struct, "SV", set_zero=.TRUE.)
     108         7232 :       CALL cp_dbcsr_sm_fm_multiply(matrix_s, vmatrix, svmatrix, ncol)
     109              : 
     110         7232 :       NULLIFY (fm_struct_tmp)
     111              :       CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=ncol, ncol_global=ncol, &
     112              :                                para_env=vmatrix%matrix_struct%para_env, &
     113         7232 :                                context=vmatrix%matrix_struct%context)
     114         7232 :       CALL cp_fm_create(overlap_vv, fm_struct_tmp, "overlap_vv")
     115         7232 :       CALL cp_fm_struct_release(fm_struct_tmp)
     116              : 
     117         7232 :       CALL parallel_gemm('T', 'N', ncol, ncol, n, rone, vmatrix, svmatrix, rzero, overlap_vv)
     118         7232 :       CALL cp_fm_cholesky_decompose(overlap_vv)
     119         7232 :       CALL cp_fm_triangular_multiply(overlap_vv, vmatrix, n_cols=ncol, side='R', invert_tr=.TRUE.)
     120              : 
     121         7232 :       CALL cp_fm_release(overlap_vv)
     122         7232 :       CALL cp_fm_release(svmatrix)
     123              : 
     124         7232 :       CALL timestop(handle)
     125              : 
     126         7360 :    END SUBROUTINE make_basis_sm
     127              : 
     128              : ! **************************************************************************************************
     129              : !> \brief returns an S-orthonormal basis v and the corresponding matrix S*v as well
     130              : !> \param vmatrix ...
     131              : !> \param ncol ...
     132              : !> \param svmatrix ...
     133              : !> \par History
     134              : !>      03.2006 created [Joost VandeVondele]
     135              : ! **************************************************************************************************
     136            0 :    SUBROUTINE make_basis_sv_fm(vmatrix, ncol, svmatrix)
     137              : 
     138              :       TYPE(cp_fm_type), INTENT(IN)                       :: vmatrix
     139              :       INTEGER, INTENT(IN)                                :: ncol
     140              :       TYPE(cp_fm_type), INTENT(IN)                       :: svmatrix
     141              : 
     142              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'make_basis_sv_fm'
     143              :       REAL(KIND=dp), PARAMETER                           :: rone = 1.0_dp, rzero = 0.0_dp
     144              : 
     145              :       INTEGER                                            :: handle, n, ncol_global
     146              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct_tmp
     147              :       TYPE(cp_fm_type)                                   :: overlap_vv
     148              : 
     149            0 :       IF (ncol == 0) RETURN
     150              : 
     151            0 :       CALL timeset(routineN, handle)
     152            0 :       NULLIFY (fm_struct_tmp)
     153              : 
     154            0 :       CALL cp_fm_get_info(matrix=vmatrix, nrow_global=n, ncol_global=ncol_global)
     155            0 :       IF (ncol > ncol_global) CPABORT("Wrong ncol value")
     156              : 
     157              :       CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=ncol, ncol_global=ncol, &
     158              :                                para_env=vmatrix%matrix_struct%para_env, &
     159            0 :                                context=vmatrix%matrix_struct%context)
     160            0 :       CALL cp_fm_create(overlap_vv, fm_struct_tmp, "overlap_vv")
     161            0 :       CALL cp_fm_struct_release(fm_struct_tmp)
     162              : 
     163            0 :       CALL parallel_gemm('T', 'N', ncol, ncol, n, rone, vmatrix, svmatrix, rzero, overlap_vv)
     164            0 :       CALL cp_fm_cholesky_decompose(overlap_vv)
     165            0 :       CALL cp_fm_triangular_multiply(overlap_vv, vmatrix, n_cols=ncol, side='R', invert_tr=.TRUE.)
     166            0 :       CALL cp_fm_triangular_multiply(overlap_vv, svmatrix, n_cols=ncol, side='R', invert_tr=.TRUE.)
     167              : 
     168            0 :       CALL cp_fm_release(overlap_vv)
     169              : 
     170            0 :       CALL timestop(handle)
     171              : 
     172            0 :    END SUBROUTINE make_basis_sv_fm
     173              : 
     174              : ! **************************************************************************************************
     175              : !> \brief ...
     176              : !> \param vmatrix ...
     177              : !> \param ncol ...
     178              : !> \param svmatrix ...
     179              : !> \param para_env ...
     180              : !> \param blacs_env ...
     181              : ! **************************************************************************************************
     182         2870 :    SUBROUTINE make_basis_sv_dbcsr(vmatrix, ncol, svmatrix, para_env, blacs_env)
     183              : 
     184              :       TYPE(dbcsr_type)                                   :: vmatrix
     185              :       INTEGER, INTENT(IN)                                :: ncol
     186              :       TYPE(dbcsr_type)                                   :: svmatrix
     187              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     188              :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env
     189              : 
     190              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'make_basis_sv_dbcsr'
     191              :       REAL(KIND=dp), PARAMETER                           :: rone = 1.0_dp, rzero = 0.0_dp
     192              : 
     193              :       INTEGER                                            :: handle, n, ncol_global
     194              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct_tmp
     195              :       TYPE(cp_fm_type)                                   :: fm_svmatrix, fm_vmatrix, overlap_vv
     196              : 
     197           86 :       IF (ncol == 0) RETURN
     198              : 
     199          464 :       CALL timeset(routineN, handle)
     200              : 
     201              :       !CALL cp_fm_get_info(matrix=vmatrix,nrow_global=n,ncol_global=ncol_global)
     202          464 :       CALL dbcsr_get_info(vmatrix, nfullrows_total=n, nfullcols_total=ncol_global)
     203          464 :       IF (ncol > ncol_global) CPABORT("Wrong ncol value")
     204              : 
     205              :       CALL cp_fm_struct_create(fm_struct_tmp, context=blacs_env, nrow_global=ncol, &
     206          464 :                                ncol_global=ncol, para_env=para_env)
     207          464 :       CALL cp_fm_create(overlap_vv, fm_struct_tmp, name="fm_overlap_vv")
     208          464 :       CALL cp_fm_struct_release(fm_struct_tmp)
     209              : 
     210              :       CALL cp_fm_struct_create(fm_struct_tmp, context=blacs_env, nrow_global=n, &
     211          464 :                                ncol_global=ncol_global, para_env=para_env)
     212          464 :       CALL cp_fm_create(fm_vmatrix, fm_struct_tmp, name="fm_vmatrix")
     213          464 :       CALL cp_fm_create(fm_svmatrix, fm_struct_tmp, name="fm_svmatrix")
     214          464 :       CALL cp_fm_struct_release(fm_struct_tmp)
     215              : 
     216          464 :       CALL copy_dbcsr_to_fm(vmatrix, fm_vmatrix)
     217          464 :       CALL copy_dbcsr_to_fm(svmatrix, fm_svmatrix)
     218              : 
     219          464 :       CALL parallel_gemm('T', 'N', ncol, ncol, n, rone, fm_vmatrix, fm_svmatrix, rzero, overlap_vv)
     220          464 :       CALL cp_fm_cholesky_decompose(overlap_vv)
     221          464 :       CALL cp_fm_triangular_multiply(overlap_vv, fm_vmatrix, n_cols=ncol, side='R', invert_tr=.TRUE.)
     222          464 :       CALL cp_fm_triangular_multiply(overlap_vv, fm_svmatrix, n_cols=ncol, side='R', invert_tr=.TRUE.)
     223              : 
     224          464 :       CALL copy_fm_to_dbcsr(fm_vmatrix, vmatrix)
     225          464 :       CALL copy_fm_to_dbcsr(fm_svmatrix, svmatrix)
     226              : 
     227          464 :       CALL cp_fm_release(overlap_vv)
     228          464 :       CALL cp_fm_release(fm_vmatrix)
     229          464 :       CALL cp_fm_release(fm_svmatrix)
     230              : 
     231          464 :       CALL timestop(handle)
     232              : 
     233          550 :    END SUBROUTINE make_basis_sv_dbcsr
     234              : 
     235              : ! **************************************************************************************************
     236              : !> \brief return a set of S orthonormal vectors (C^T S C == 1) where
     237              : !>      the cholesky decomposed form of S is passed as an argument
     238              : !> \param vmatrix ...
     239              : !> \param ncol ...
     240              : !> \param ortho cholesky decomposed S matrix
     241              : !> \par History
     242              : !>      03.2006 created [Joost VandeVondele]
     243              : !> \note
     244              : !>      if the cholesky decomposed S matrix is not available
     245              : !>      use make_basis_sm since this is much faster than computing the
     246              : !>      cholesky decomposition of S
     247              : ! **************************************************************************************************
     248        25128 :    SUBROUTINE make_basis_cholesky(vmatrix, ncol, ortho)
     249              : 
     250              :       TYPE(cp_fm_type), INTENT(IN)                       :: vmatrix
     251              :       INTEGER, INTENT(IN)                                :: ncol
     252              :       TYPE(cp_fm_type), INTENT(IN)                       :: ortho
     253              : 
     254              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'make_basis_cholesky'
     255              :       REAL(KIND=dp), PARAMETER                           :: rone = 1.0_dp, rzero = 0.0_dp
     256              : 
     257              :       INTEGER                                            :: handle, n, ncol_global
     258              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct_tmp
     259              :       TYPE(cp_fm_type)                                   :: overlap_vv
     260              : 
     261           80 :       IF (ncol == 0) RETURN
     262              : 
     263         6262 :       CALL timeset(routineN, handle)
     264         6262 :       NULLIFY (fm_struct_tmp)
     265              : 
     266         6262 :       CALL cp_fm_get_info(matrix=vmatrix, nrow_global=n, ncol_global=ncol_global)
     267         6262 :       IF (ncol > ncol_global) CPABORT("Wrong ncol value")
     268              : 
     269              :       CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=ncol, ncol_global=ncol, &
     270              :                                para_env=vmatrix%matrix_struct%para_env, &
     271         6262 :                                context=vmatrix%matrix_struct%context)
     272         6262 :       CALL cp_fm_create(overlap_vv, fm_struct_tmp, "overlap_vv")
     273         6262 :       CALL cp_fm_struct_release(fm_struct_tmp)
     274              : 
     275         6262 :       CALL cp_fm_triangular_multiply(ortho, vmatrix, n_cols=ncol)
     276         6262 :       CALL cp_fm_syrk('U', 'T', n, rone, vmatrix, 1, 1, rzero, overlap_vv)
     277         6262 :       CALL cp_fm_cholesky_decompose(overlap_vv)
     278         6262 :       CALL cp_fm_triangular_multiply(overlap_vv, vmatrix, n_cols=ncol, side='R', invert_tr=.TRUE.)
     279         6262 :       CALL cp_fm_triangular_multiply(ortho, vmatrix, n_cols=ncol, invert_tr=.TRUE.)
     280              : 
     281         6262 :       CALL cp_fm_release(overlap_vv)
     282              : 
     283         6262 :       CALL timestop(handle)
     284              : 
     285         6342 :    END SUBROUTINE make_basis_cholesky
     286              : 
     287              : ! **************************************************************************************************
     288              : !> \brief return a set of S orthonormal vectors (C^T S C == 1) where
     289              : !>      a Loedwin transformation is applied to keep the rotated vectors as close
     290              : !>      as possible to the original ones
     291              : !> \param vmatrix ...
     292              : !> \param ncol ...
     293              : !> \param matrix_s ...
     294              : !> \param
     295              : !> \par History
     296              : !>      05.2009 created [MI]
     297              : !> \note
     298              : ! **************************************************************************************************
     299         7932 :    SUBROUTINE make_basis_lowdin(vmatrix, ncol, matrix_s)
     300              : 
     301              :       TYPE(cp_fm_type), INTENT(IN)                       :: vmatrix
     302              :       INTEGER, INTENT(IN)                                :: ncol
     303              :       TYPE(dbcsr_type)                                   :: matrix_s
     304              : 
     305              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'make_basis_lowdin'
     306              :       REAL(KIND=dp), PARAMETER                           :: rone = 1.0_dp, rzero = 0.0_dp
     307              : 
     308              :       INTEGER                                            :: handle, n, ncol_global, ndep
     309              :       REAL(dp)                                           :: threshold
     310              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct_tmp
     311              :       TYPE(cp_fm_type)                                   :: csc, sc, work
     312              : 
     313            0 :       IF (ncol == 0) RETURN
     314              : 
     315         1322 :       CALL timeset(routineN, handle)
     316         1322 :       NULLIFY (fm_struct_tmp)
     317         1322 :       threshold = 1.0E-7_dp
     318         1322 :       CALL cp_fm_get_info(matrix=vmatrix, nrow_global=n, ncol_global=ncol_global)
     319         1322 :       IF (ncol > ncol_global) CPABORT("Wrong ncol value")
     320              : 
     321         1322 :       CALL cp_fm_create(sc, vmatrix%matrix_struct, "SC")
     322         1322 :       CALL cp_dbcsr_sm_fm_multiply(matrix_s, vmatrix, sc, ncol)
     323              : 
     324         1322 :       NULLIFY (fm_struct_tmp)
     325              :       CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=ncol, ncol_global=ncol, &
     326              :                                para_env=vmatrix%matrix_struct%para_env, &
     327         1322 :                                context=vmatrix%matrix_struct%context)
     328         1322 :       CALL cp_fm_create(csc, fm_struct_tmp, "csc")
     329         1322 :       CALL cp_fm_set_all(csc, 0.0_dp)
     330         1322 :       CALL cp_fm_create(work, fm_struct_tmp, "work")
     331         1322 :       CALL cp_fm_set_all(work, 0.0_dp)
     332         1322 :       CALL cp_fm_struct_release(fm_struct_tmp)
     333              : 
     334         1322 :       CALL parallel_gemm('T', 'N', ncol, ncol, n, rone, vmatrix, sc, rzero, csc)
     335         1322 :       CALL cp_fm_power(csc, work, -0.5_dp, threshold, ndep)
     336         1322 :       CALL parallel_gemm('N', 'N', n, ncol, ncol, rone, vmatrix, csc, rzero, sc)
     337         1322 :       CALL cp_fm_to_fm(sc, vmatrix, ncol, 1, 1)
     338              : 
     339         1322 :       CALL cp_fm_release(csc)
     340         1322 :       CALL cp_fm_release(sc)
     341         1322 :       CALL cp_fm_release(work)
     342              : 
     343         1322 :       CALL timestop(handle)
     344              : 
     345         1322 :    END SUBROUTINE make_basis_lowdin
     346              : 
     347              : ! **************************************************************************************************
     348              : !> \brief given a set of vectors, return an orthogonal (C^T C == 1) set
     349              : !>      spanning the same space (notice, only for cases where S==1)
     350              : !> \param vmatrix ...
     351              : !> \param ncol ...
     352              : !> \par History
     353              : !>      03.2006 created [Joost VandeVondele]
     354              : ! **************************************************************************************************
     355        14606 :    SUBROUTINE make_basis_simple(vmatrix, ncol)
     356              : 
     357              :       TYPE(cp_fm_type), INTENT(IN)                       :: vmatrix
     358              :       INTEGER, INTENT(IN)                                :: ncol
     359              : 
     360              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'make_basis_simple'
     361              :       REAL(KIND=dp), PARAMETER                           :: rone = 1.0_dp, rzero = 0.0_dp
     362              : 
     363              :       INTEGER                                            :: handle, n, ncol_global
     364              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct_tmp
     365              :       TYPE(cp_fm_type)                                   :: overlap_vv
     366              : 
     367           70 :       IF (ncol == 0) RETURN
     368              : 
     369         3634 :       CALL timeset(routineN, handle)
     370              : 
     371         3634 :       NULLIFY (fm_struct_tmp)
     372              : 
     373         3634 :       CALL cp_fm_get_info(matrix=vmatrix, nrow_global=n, ncol_global=ncol_global)
     374         3634 :       IF (ncol > ncol_global) CPABORT("Wrong ncol value")
     375              : 
     376              :       CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=ncol, ncol_global=ncol, &
     377              :                                para_env=vmatrix%matrix_struct%para_env, &
     378         3634 :                                context=vmatrix%matrix_struct%context)
     379         3634 :       CALL cp_fm_create(overlap_vv, fm_struct_tmp, "overlap_vv")
     380         3634 :       CALL cp_fm_struct_release(fm_struct_tmp)
     381              : 
     382         3634 :       CALL parallel_gemm('T', 'N', ncol, ncol, n, rone, vmatrix, vmatrix, rzero, overlap_vv)
     383         3634 :       CALL cp_fm_cholesky_decompose(overlap_vv)
     384         3634 :       CALL cp_fm_triangular_multiply(overlap_vv, vmatrix, n_cols=ncol, side='R', invert_tr=.TRUE.)
     385              : 
     386         3634 :       CALL cp_fm_release(overlap_vv)
     387              : 
     388         3634 :       CALL timestop(handle)
     389              : 
     390         3704 :    END SUBROUTINE make_basis_simple
     391              : 
     392              : ! **************************************************************************************************
     393              : !> \brief computes ritz values of a set of orbitals given a ks_matrix
     394              : !>      rotates the orbitals into eigenstates depending on do_rotation
     395              : !>      writes the evals to the screen depending on ionode/scr
     396              : !> \param orbitals S-orthonormal orbitals
     397              : !> \param ks_matrix Kohn-Sham matrix
     398              : !> \param evals_arg optional, filled with the evals
     399              : !> \param ionode , scr if present write to unit scr where ionode
     400              : !> \param scr ...
     401              : !> \param do_rotation optional rotate orbitals (default=.TRUE.)
     402              : !>        note that rotating the orbitals is slower
     403              : !> \param co_rotate an optional set of orbitals rotated by the same rotation matrix
     404              : !> \param co_rotate_dbcsr ...
     405              : !> \par History
     406              : !>      08.2004 documented and added do_rotation [Joost VandeVondele]
     407              : !>      09.2008 only compute eigenvalues if rotation is not needed
     408              : ! **************************************************************************************************
     409         8179 :    SUBROUTINE subspace_eigenvalues_ks_fm(orbitals, ks_matrix, evals_arg, ionode, scr, &
     410              :                                          do_rotation, co_rotate, co_rotate_dbcsr)
     411              : 
     412              :       TYPE(cp_fm_type), INTENT(IN)                       :: orbitals
     413              :       TYPE(dbcsr_type), POINTER                          :: ks_matrix
     414              :       REAL(KIND=dp), DIMENSION(:), OPTIONAL              :: evals_arg
     415              :       LOGICAL, INTENT(IN), OPTIONAL                      :: ionode
     416              :       INTEGER, INTENT(IN), OPTIONAL                      :: scr
     417              :       LOGICAL, INTENT(IN), OPTIONAL                      :: do_rotation
     418              :       TYPE(cp_fm_type), INTENT(IN), OPTIONAL             :: co_rotate
     419              :       TYPE(dbcsr_type), OPTIONAL, POINTER                :: co_rotate_dbcsr
     420              : 
     421              :       CHARACTER(len=*), PARAMETER :: routineN = 'subspace_eigenvalues_ks_fm'
     422              : 
     423              :       INTEGER                                            :: handle, i, j, n, ncol_global, nrow_global
     424              :       LOGICAL                                            :: compute_evecs, do_rotation_local
     425         8179 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: evals
     426              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct_tmp
     427              :       TYPE(cp_fm_type)                                   :: e_vectors, h_block, weighted_vectors, &
     428              :                                                             weighted_vectors2
     429              : 
     430         8179 :       CALL timeset(routineN, handle)
     431              : 
     432         8179 :       do_rotation_local = .TRUE.
     433         8179 :       IF (PRESENT(do_rotation)) do_rotation_local = do_rotation
     434              : 
     435         8179 :       NULLIFY (fm_struct_tmp)
     436              :       CALL cp_fm_get_info(matrix=orbitals, &
     437              :                           ncol_global=ncol_global, &
     438         8179 :                           nrow_global=nrow_global)
     439              : 
     440              :       IF (do_rotation_local) THEN
     441              :          compute_evecs = .TRUE.
     442              :       ELSE
     443              :          ! this would be the logical choice if syevx computing only evals were faster than syevd computing evecs and evals.
     444              :          compute_evecs = .FALSE.
     445              :          ! this is not the case, so lets compute evecs always
     446              :          compute_evecs = .TRUE.
     447              :       END IF
     448              : 
     449         8179 :       IF (ncol_global > 0) THEN
     450              : 
     451        24279 :          ALLOCATE (evals(ncol_global))
     452              : 
     453         8093 :          CALL cp_fm_create(weighted_vectors, orbitals%matrix_struct, "weighted_vectors")
     454              :          CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=ncol_global, ncol_global=ncol_global, &
     455              :                                   para_env=orbitals%matrix_struct%para_env, &
     456         8093 :                                   context=orbitals%matrix_struct%context)
     457         8093 :          CALL cp_fm_create(h_block, fm_struct_tmp, name="h block")
     458         8093 :          IF (compute_evecs) THEN
     459         8093 :             CALL cp_fm_create(e_vectors, fm_struct_tmp, name="e vectors")
     460              :          END IF
     461         8093 :          CALL cp_fm_struct_release(fm_struct_tmp)
     462              : 
     463              :          ! h subblock and diag
     464         8093 :          CALL cp_dbcsr_sm_fm_multiply(ks_matrix, orbitals, weighted_vectors, ncol_global)
     465              : 
     466              :          CALL parallel_gemm('T', 'N', ncol_global, ncol_global, nrow_global, 1.0_dp, &
     467         8093 :                             orbitals, weighted_vectors, 0.0_dp, h_block)
     468              : 
     469              :          ! if eigenvectors are required, go for syevd, otherwise only compute eigenvalues
     470              :          IF (compute_evecs) THEN
     471         8093 :             CALL choose_eigv_solver(h_block, e_vectors, evals)
     472              :          ELSE
     473              :             CALL cp_fm_syevx(h_block, eigenvalues=evals)
     474              :          END IF
     475              : 
     476              :          ! rotate the orbitals
     477         8093 :          IF (do_rotation_local) THEN
     478              :             CALL parallel_gemm('N', 'N', nrow_global, ncol_global, ncol_global, 1.0_dp, &
     479         7809 :                                orbitals, e_vectors, 0.0_dp, weighted_vectors)
     480         7809 :             CALL cp_fm_to_fm(weighted_vectors, orbitals)
     481         7809 :             IF (PRESENT(co_rotate)) THEN
     482              :                CALL parallel_gemm('N', 'N', nrow_global, ncol_global, ncol_global, 1.0_dp, &
     483            0 :                                   co_rotate, e_vectors, 0.0_dp, weighted_vectors)
     484            0 :                CALL cp_fm_to_fm(weighted_vectors, co_rotate)
     485              :             END IF
     486         7809 :             IF (PRESENT(co_rotate_dbcsr)) THEN
     487          362 :                IF (ASSOCIATED(co_rotate_dbcsr)) THEN
     488          358 :                   CALL cp_fm_create(weighted_vectors2, orbitals%matrix_struct, "weighted_vectors")
     489          358 :                   CALL copy_dbcsr_to_fm(co_rotate_dbcsr, weighted_vectors2)
     490              :                   CALL parallel_gemm('N', 'N', nrow_global, ncol_global, ncol_global, 1.0_dp, &
     491          358 :                                      weighted_vectors2, e_vectors, 0.0_dp, weighted_vectors)
     492          358 :                   CALL copy_fm_to_dbcsr(weighted_vectors, co_rotate_dbcsr)
     493          358 :                   CALL cp_fm_release(weighted_vectors2)
     494              :                END IF
     495              :             END IF
     496              :          END IF
     497              : 
     498              :          ! give output
     499         8093 :          IF (PRESENT(evals_arg)) THEN
     500         8061 :             n = MIN(SIZE(evals_arg), SIZE(evals))
     501        81987 :             evals_arg(1:n) = evals(1:n)
     502              :          END IF
     503              : 
     504         8093 :          IF (PRESENT(ionode) .OR. PRESENT(scr)) THEN
     505          180 :             IF (.NOT. PRESENT(ionode)) CPABORT("IONODE?")
     506          180 :             IF (.NOT. PRESENT(scr)) CPABORT("SCR?")
     507          180 :             IF (ionode) THEN
     508          225 :                DO i = 1, ncol_global, 4
     509          135 :                   j = MIN(3, ncol_global - i)
     510           90 :                   SELECT CASE (j)
     511              :                   CASE (3)
     512          104 :                      WRITE (scr, '(1X,4F16.8)') evals(i:i + j)
     513              :                   CASE (2)
     514            2 :                      WRITE (scr, '(1X,3F16.8)') evals(i:i + j)
     515              :                   CASE (1)
     516            7 :                      WRITE (scr, '(1X,2F16.8)') evals(i:i + j)
     517              :                   CASE (0)
     518          135 :                      WRITE (scr, '(1X,1F16.8)') evals(i:i + j)
     519              :                   END SELECT
     520              :                END DO
     521              :             END IF
     522              :          END IF
     523              : 
     524         8093 :          CALL cp_fm_release(weighted_vectors)
     525         8093 :          CALL cp_fm_release(h_block)
     526              :          IF (compute_evecs) THEN
     527         8093 :             CALL cp_fm_release(e_vectors)
     528              :          END IF
     529              : 
     530        24279 :          DEALLOCATE (evals)
     531              : 
     532              :       END IF
     533              : 
     534         8179 :       CALL timestop(handle)
     535              : 
     536        16358 :    END SUBROUTINE subspace_eigenvalues_ks_fm
     537              : 
     538              : ! **************************************************************************************************
     539              : !> \brief ...
     540              : !> \param orbitals ...
     541              : !> \param ks_matrix ...
     542              : !> \param evals_arg ...
     543              : !> \param ionode ...
     544              : !> \param scr ...
     545              : !> \param do_rotation ...
     546              : !> \param co_rotate ...
     547              : !> \param para_env ...
     548              : !> \param blacs_env ...
     549              : ! **************************************************************************************************
     550         6290 :    SUBROUTINE subspace_eigenvalues_ks_dbcsr(orbitals, ks_matrix, evals_arg, ionode, scr, &
     551              :                                             do_rotation, co_rotate, para_env, blacs_env)
     552              : 
     553              :       TYPE(dbcsr_type), POINTER                          :: orbitals, ks_matrix
     554              :       REAL(KIND=dp), DIMENSION(:), OPTIONAL              :: evals_arg
     555              :       LOGICAL, INTENT(IN), OPTIONAL                      :: ionode
     556              :       INTEGER, INTENT(IN), OPTIONAL                      :: scr
     557              :       LOGICAL, INTENT(IN), OPTIONAL                      :: do_rotation
     558              :       TYPE(dbcsr_type), OPTIONAL, POINTER                :: co_rotate
     559              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     560              :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env
     561              : 
     562              :       CHARACTER(len=*), PARAMETER :: routineN = 'subspace_eigenvalues_ks_dbcsr'
     563              : 
     564              :       INTEGER                                            :: handle, i, j, ncol_global, nrow_global
     565              :       LOGICAL                                            :: compute_evecs, do_rotation_local
     566         6290 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: evals
     567              :       TYPE(dbcsr_type), POINTER                          :: e_vectors, h_block, weighted_vectors
     568              : 
     569         6290 :       CALL timeset(routineN, handle)
     570              : 
     571         6290 :       do_rotation_local = .TRUE.
     572         6290 :       IF (PRESENT(do_rotation)) do_rotation_local = do_rotation
     573              : 
     574         6290 :       NULLIFY (e_vectors, h_block, weighted_vectors)
     575              : 
     576              :       CALL dbcsr_get_info(matrix=orbitals, &
     577              :                           nfullcols_total=ncol_global, &
     578         6290 :                           nfullrows_total=nrow_global)
     579              : 
     580              :       IF (do_rotation_local) THEN
     581              :          compute_evecs = .TRUE.
     582              :       ELSE
     583              :          ! this would be the logical choice if syevx computing only evals were faster than syevd computing evecs and evals.
     584              :          compute_evecs = .FALSE.
     585              :          ! this is not the case, so lets compute evecs always
     586              :          compute_evecs = .TRUE.
     587              :       END IF
     588              : 
     589         6290 :       IF (ncol_global > 0) THEN
     590              : 
     591        18234 :          ALLOCATE (evals(ncol_global))
     592              : 
     593         6078 :          CALL dbcsr_init_p(weighted_vectors)
     594         6078 :          CALL dbcsr_copy(weighted_vectors, orbitals, name="weighted_vectors")
     595              : 
     596         6078 :          CALL dbcsr_init_p(h_block)
     597              :          CALL cp_dbcsr_m_by_n_from_template(h_block, template=orbitals, m=ncol_global, n=ncol_global, &
     598         6078 :                                             sym=dbcsr_type_no_symmetry)
     599              : 
     600              : !!!!!!!!!!!!!!XXXXXXXXXXXXXXXXXXX!!!!!!!!!!!!!
     601              :          IF (compute_evecs) THEN
     602         6078 :             CALL dbcsr_init_p(e_vectors)
     603              :             CALL cp_dbcsr_m_by_n_from_template(e_vectors, template=orbitals, m=ncol_global, n=ncol_global, &
     604         6078 :                                                sym=dbcsr_type_no_symmetry)
     605              :          END IF
     606              : 
     607              :          ! h subblock and diag
     608              :          CALL dbcsr_multiply('N', 'N', 1.0_dp, ks_matrix, orbitals, &
     609         6078 :                              0.0_dp, weighted_vectors)
     610              :          !CALL cp_dbcsr_sm_fm_multiply(ks_matrix,orbitals,weighted_vectors, ncol_global)
     611              : 
     612         6078 :          CALL dbcsr_multiply('T', 'N', 1.0_dp, orbitals, weighted_vectors, 0.0_dp, h_block)
     613              :          !CALL parallel_gemm('T','N',ncol_global,ncol_global,nrow_global,1.0_dp, &
     614              :          !                orbitals,weighted_vectors,0.0_dp,h_block)
     615              : 
     616              :          ! if eigenvectors are required, go for syevd, otherwise only compute eigenvalues
     617              :          IF (compute_evecs) THEN
     618         6078 :             CALL cp_dbcsr_syevd(h_block, e_vectors, evals, para_env=para_env, blacs_env=blacs_env)
     619              :          ELSE
     620              :             CALL cp_dbcsr_syevx(h_block, eigenvalues=evals, para_env=para_env, blacs_env=blacs_env)
     621              :          END IF
     622              : 
     623              :          ! rotate the orbitals
     624         6078 :          IF (do_rotation_local) THEN
     625         2972 :             CALL dbcsr_multiply('N', 'N', 1.0_dp, orbitals, e_vectors, 0.0_dp, weighted_vectors)
     626              :             !CALL parallel_gemm('N','N',nrow_global,ncol_global,ncol_global,1.0_dp, &
     627              :             !             orbitals,e_vectors,0.0_dp,weighted_vectors)
     628         2972 :             CALL dbcsr_copy(orbitals, weighted_vectors)
     629              :             !CALL cp_fm_to_fm(weighted_vectors,orbitals)
     630         2972 :             IF (PRESENT(co_rotate)) THEN
     631         2954 :                IF (ASSOCIATED(co_rotate)) THEN
     632         2954 :                   CALL dbcsr_multiply('N', 'N', 1.0_dp, co_rotate, e_vectors, 0.0_dp, weighted_vectors)
     633              :                   !CALL parallel_gemm('N','N',nrow_global,ncol_global,ncol_global,1.0_dp, &
     634              :                   !     co_rotate,e_vectors,0.0_dp,weighted_vectors)
     635         2954 :                   CALL dbcsr_copy(co_rotate, weighted_vectors)
     636              :                   !CALL cp_fm_to_fm(weighted_vectors,co_rotate)
     637              :                END IF
     638              :             END IF
     639              :          END IF
     640              : 
     641              :          ! give output
     642         6078 :          IF (PRESENT(evals_arg)) THEN
     643        19182 :             evals_arg(:) = evals(:)
     644              :          END IF
     645              : 
     646         6078 :          IF (PRESENT(ionode) .OR. PRESENT(scr)) THEN
     647            0 :             IF (.NOT. PRESENT(ionode)) CPABORT("IONODE?")
     648            0 :             IF (.NOT. PRESENT(scr)) CPABORT("SCR?")
     649            0 :             IF (ionode) THEN
     650            0 :                DO i = 1, ncol_global, 4
     651            0 :                   j = MIN(3, ncol_global - i)
     652            0 :                   SELECT CASE (j)
     653              :                   CASE (3)
     654            0 :                      WRITE (scr, '(1X,4F16.8)') evals(i:i + j)
     655              :                   CASE (2)
     656            0 :                      WRITE (scr, '(1X,3F16.8)') evals(i:i + j)
     657              :                   CASE (1)
     658            0 :                      WRITE (scr, '(1X,2F16.8)') evals(i:i + j)
     659              :                   CASE (0)
     660            0 :                      WRITE (scr, '(1X,1F16.8)') evals(i:i + j)
     661              :                   END SELECT
     662              :                END DO
     663              :             END IF
     664              :          END IF
     665              : 
     666         6078 :          CALL dbcsr_release_p(weighted_vectors)
     667         6078 :          CALL dbcsr_release_p(h_block)
     668              :          IF (compute_evecs) THEN
     669         6078 :             CALL dbcsr_release_p(e_vectors)
     670              :          END IF
     671              : 
     672         6078 :          DEALLOCATE (evals)
     673              : 
     674              :       END IF
     675              : 
     676         6290 :       CALL timestop(handle)
     677              : 
     678         6290 :    END SUBROUTINE subspace_eigenvalues_ks_dbcsr
     679              : 
     680              : ! computes the effective orthonormality of a set of mos given an s-matrix
     681              : ! orthonormality is the max deviation from unity of the C^T S C
     682              : ! **************************************************************************************************
     683              : !> \brief ...
     684              : !> \param orthonormality ...
     685              : !> \param mo_array ...
     686              : !> \param matrix_s ...
     687              : ! **************************************************************************************************
     688         1376 :    SUBROUTINE calculate_orthonormality(orthonormality, mo_array, matrix_s)
     689              :       REAL(KIND=dp)                                      :: orthonormality
     690              :       TYPE(mo_set_type), DIMENSION(:), INTENT(IN)        :: mo_array
     691              :       TYPE(dbcsr_type), OPTIONAL, POINTER                :: matrix_s
     692              : 
     693              :       CHARACTER(len=*), PARAMETER :: routineN = 'calculate_orthonormality'
     694              : 
     695              :       INTEGER                                            :: handle, i, ispin, j, k, n, ncol_local, &
     696              :                                                             nrow_local, nspin
     697         1376 :       INTEGER, DIMENSION(:), POINTER                     :: col_indices, row_indices
     698              :       REAL(KIND=dp)                                      :: alpha, max_alpha
     699              :       TYPE(cp_fm_struct_type), POINTER                   :: tmp_fm_struct
     700              :       TYPE(cp_fm_type)                                   :: overlap, svec
     701              : 
     702         1376 :       NULLIFY (tmp_fm_struct)
     703              : 
     704         1376 :       CALL timeset(routineN, handle)
     705              : 
     706         1376 :       nspin = SIZE(mo_array)
     707         1376 :       max_alpha = 0.0_dp
     708              : 
     709         2764 :       DO ispin = 1, nspin
     710         1388 :          IF (PRESENT(matrix_s)) THEN
     711              :             ! get S*C
     712         1330 :             CALL cp_fm_create(svec, mo_array(ispin)%mo_coeff%matrix_struct)
     713              :             CALL cp_fm_get_info(mo_array(ispin)%mo_coeff, &
     714         1330 :                                 nrow_global=n, ncol_global=k)
     715              :             CALL cp_dbcsr_sm_fm_multiply(matrix_s, mo_array(ispin)%mo_coeff, &
     716         1330 :                                          svec, k)
     717              :             ! get C^T (S*C)
     718              :             CALL cp_fm_struct_create(tmp_fm_struct, nrow_global=k, ncol_global=k, &
     719              :                                      para_env=mo_array(ispin)%mo_coeff%matrix_struct%para_env, &
     720         1330 :                                      context=mo_array(ispin)%mo_coeff%matrix_struct%context)
     721         1330 :             CALL cp_fm_create(overlap, tmp_fm_struct)
     722         1330 :             CALL cp_fm_struct_release(tmp_fm_struct)
     723              :             CALL parallel_gemm('T', 'N', k, k, n, 1.0_dp, mo_array(ispin)%mo_coeff, &
     724         1330 :                                svec, 0.0_dp, overlap)
     725         1330 :             CALL cp_fm_release(svec)
     726              :          ELSE
     727              :             ! orthogonal basis C^T C
     728              :             CALL cp_fm_get_info(mo_array(ispin)%mo_coeff, &
     729           58 :                                 nrow_global=n, ncol_global=k)
     730              :             CALL cp_fm_struct_create(tmp_fm_struct, nrow_global=k, ncol_global=k, &
     731              :                                      para_env=mo_array(ispin)%mo_coeff%matrix_struct%para_env, &
     732           58 :                                      context=mo_array(ispin)%mo_coeff%matrix_struct%context)
     733           58 :             CALL cp_fm_create(overlap, tmp_fm_struct)
     734           58 :             CALL cp_fm_struct_release(tmp_fm_struct)
     735              :             CALL parallel_gemm('T', 'N', k, k, n, 1.0_dp, mo_array(ispin)%mo_coeff, &
     736           58 :                                mo_array(ispin)%mo_coeff, 0.0_dp, overlap)
     737              :          END IF
     738              :          CALL cp_fm_get_info(overlap, nrow_local=nrow_local, ncol_local=ncol_local, &
     739         1388 :                              row_indices=row_indices, col_indices=col_indices)
     740         9835 :          DO i = 1, nrow_local
     741       453292 :             DO j = 1, ncol_local
     742       443457 :                alpha = overlap%local_data(i, j)
     743       443457 :                IF (row_indices(i) == col_indices(j)) alpha = alpha - 1.0_dp
     744       451904 :                max_alpha = MAX(max_alpha, ABS(alpha))
     745              :             END DO
     746              :          END DO
     747         4152 :          CALL cp_fm_release(overlap)
     748              :       END DO
     749         1376 :       CALL mo_array(1)%mo_coeff%matrix_struct%para_env%max(max_alpha)
     750         1376 :       orthonormality = max_alpha
     751              :       ! write(*,*) "max deviation from orthonormalization ",orthonormality
     752              : 
     753         1376 :       CALL timestop(handle)
     754              : 
     755         1376 :    END SUBROUTINE calculate_orthonormality
     756              : 
     757              : ! computes the minimum/maximum magnitudes of C^T C. This could be useful
     758              : ! to detect problems in the case of nearly singular overlap matrices.
     759              : ! in this case, we expect the ratio of min/max to be large
     760              : ! this routine is only similar to mo_orthonormality if S==1
     761              : ! **************************************************************************************************
     762              : !> \brief ...
     763              : !> \param mo_array ...
     764              : !> \param mo_mag_min ...
     765              : !> \param mo_mag_max ...
     766              : ! **************************************************************************************************
     767         1356 :    SUBROUTINE calculate_magnitude(mo_array, mo_mag_min, mo_mag_max)
     768              :       TYPE(mo_set_type), DIMENSION(:), INTENT(IN)        :: mo_array
     769              :       REAL(KIND=dp)                                      :: mo_mag_min, mo_mag_max
     770              : 
     771              :       CHARACTER(len=*), PARAMETER :: routineN = 'calculate_magnitude'
     772              : 
     773              :       INTEGER                                            :: handle, ispin, k, n, nspin
     774         1356 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: evals
     775              :       TYPE(cp_fm_struct_type), POINTER                   :: tmp_fm_struct
     776              :       TYPE(cp_fm_type)                                   :: evecs, overlap
     777              : 
     778         1356 :       NULLIFY (tmp_fm_struct)
     779              : 
     780         1356 :       CALL timeset(routineN, handle)
     781              : 
     782         1356 :       nspin = SIZE(mo_array)
     783         1356 :       mo_mag_min = HUGE(0.0_dp)
     784         1356 :       mo_mag_max = -HUGE(0.0_dp)
     785         2712 :       DO ispin = 1, nspin
     786              :          CALL cp_fm_get_info(mo_array(ispin)%mo_coeff, &
     787         1356 :                              nrow_global=n, ncol_global=k)
     788         4068 :          ALLOCATE (evals(k))
     789              :          CALL cp_fm_struct_create(tmp_fm_struct, nrow_global=k, ncol_global=k, &
     790              :                                   para_env=mo_array(ispin)%mo_coeff%matrix_struct%para_env, &
     791         1356 :                                   context=mo_array(ispin)%mo_coeff%matrix_struct%context)
     792         1356 :          CALL cp_fm_create(overlap, tmp_fm_struct)
     793         1356 :          CALL cp_fm_create(evecs, tmp_fm_struct)
     794         1356 :          CALL cp_fm_struct_release(tmp_fm_struct)
     795              :          CALL parallel_gemm('T', 'N', k, k, n, 1.0_dp, mo_array(ispin)%mo_coeff, &
     796         1356 :                             mo_array(ispin)%mo_coeff, 0.0_dp, overlap)
     797         1356 :          CALL choose_eigv_solver(overlap, evecs, evals)
     798        19474 :          mo_mag_min = MIN(MINVAL(evals), mo_mag_min)
     799        19474 :          mo_mag_max = MAX(MAXVAL(evals), mo_mag_max)
     800         1356 :          CALL cp_fm_release(overlap)
     801         1356 :          CALL cp_fm_release(evecs)
     802         5424 :          DEALLOCATE (evals)
     803              :       END DO
     804         1356 :       CALL timestop(handle)
     805              : 
     806         2712 :    END SUBROUTINE calculate_magnitude
     807              : 
     808              : ! **************************************************************************************************
     809              : !> \brief  Calculate KS eigenvalues starting from  OF MOS
     810              : !> \param mos ...
     811              : !> \param nspins ...
     812              : !> \param ks_rmpv ...
     813              : !> \param scf_control ...
     814              : !> \param mo_derivs ...
     815              : !> \param admm_env ...
     816              : !> \param hairy_probes ...
     817              : !> \param probe ...
     818              : !> \par History
     819              : !>         02.2013 moved from qs_scf_post_gpw
     820              : !>
     821              : ! **************************************************************************************************
     822          202 :    SUBROUTINE make_mo_eig(mos, nspins, ks_rmpv, scf_control, mo_derivs, admm_env, &
     823              :                           hairy_probes, probe)
     824              : 
     825              :       TYPE(mo_set_type), DIMENSION(:), INTENT(INOUT)     :: mos
     826              :       INTEGER, INTENT(IN)                                :: nspins
     827              :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: ks_rmpv
     828              :       TYPE(scf_control_type), POINTER                    :: scf_control
     829              :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: mo_derivs
     830              :       TYPE(admm_type), OPTIONAL, POINTER                 :: admm_env
     831              :       LOGICAL, OPTIONAL                                  :: hairy_probes
     832              :       TYPE(hairy_probes_type), DIMENSION(:), OPTIONAL, &
     833              :          POINTER                                         :: probe
     834              : 
     835              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'make_mo_eig'
     836              : 
     837              :       INTEGER                                            :: handle, homo, ispin, nmo, output_unit
     838          202 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: mo_eigenvalues
     839              :       TYPE(cp_fm_type), POINTER                          :: mo_coeff
     840              :       TYPE(dbcsr_type), POINTER                          :: mo_coeff_deriv
     841              : 
     842          202 :       CALL timeset(routineN, handle)
     843              : 
     844          202 :       NULLIFY (mo_coeff_deriv, mo_coeff, mo_eigenvalues)
     845          202 :       output_unit = cp_logger_get_default_io_unit()
     846              : 
     847          444 :       DO ispin = 1, nspins
     848              :          CALL get_mo_set(mo_set=mos(ispin), mo_coeff=mo_coeff, &
     849          242 :                          eigenvalues=mo_eigenvalues, homo=homo, nmo=nmo)
     850          242 :          IF (output_unit > 0) WRITE (output_unit, *) " "
     851          242 :          IF (output_unit > 0) WRITE (output_unit, *) " Eigenvalues of the occupied subspace spin ", ispin
     852              :          !      IF (homo /= nmo) THEN
     853              :          !         IF (output_unit>0) WRITE(output_unit,*)" and ",nmo-homo," added MO eigenvalues"
     854              :          !      END IF
     855          242 :          IF (output_unit > 0) WRITE (output_unit, *) "---------------------------------------------"
     856              : 
     857          242 :          IF (scf_control%use_ot) THEN
     858              :             ! Also rotate the OT derivs, since they are needed for force calculations
     859          128 :             IF (ASSOCIATED(mo_derivs)) THEN
     860          128 :                mo_coeff_deriv => mo_derivs(ispin)%matrix
     861              :             ELSE
     862            0 :                mo_coeff_deriv => NULL()
     863              :             END IF
     864              : 
     865              :             ! If we do ADMM, we add have to modify the Kohn-Sham matrix
     866          128 :             IF (PRESENT(admm_env)) THEN
     867            0 :                CALL admm_correct_for_eigenvalues(ispin, admm_env, ks_rmpv(ispin)%matrix)
     868              :             END IF
     869              : 
     870              :             CALL calculate_subspace_eigenvalues(mo_coeff, ks_rmpv(ispin)%matrix, mo_eigenvalues, &
     871              :                                                 scr=output_unit, ionode=output_unit > 0, do_rotation=.TRUE., &
     872          128 :                                                 co_rotate_dbcsr=mo_coeff_deriv)
     873              : 
     874              :             ! If we do ADMM, we restore the original Kohn-Sham matrix
     875          128 :             IF (PRESENT(admm_env)) THEN
     876            0 :                CALL admm_uncorrect_for_eigenvalues(ispin, admm_env, ks_rmpv(ispin)%matrix)
     877              :             END IF
     878              :          ELSE
     879          114 :             IF (output_unit > 0) WRITE (output_unit, '(4(1X,1F16.8))') mo_eigenvalues(1:homo)
     880              :          END IF
     881          242 :          IF (.NOT. scf_control%diagonalization%mom) THEN
     882          242 :             IF (PRESENT(hairy_probes) .EQV. .TRUE.) THEN
     883            0 :                scf_control%smear%do_smear = .FALSE.
     884              :                CALL set_mo_occupation(mo_set=mos(ispin), &
     885              :                                       smear=scf_control%smear, &
     886            0 :                                       probe=probe)
     887              :             ELSE
     888          242 :                CALL set_mo_occupation(mo_set=mos(ispin), smear=scf_control%smear)
     889              :             END IF
     890              :          END IF
     891          242 :          IF (output_unit > 0) WRITE (output_unit, '(T2,A,F12.6)') &
     892          565 :             "Fermi Energy [eV] :", mos(ispin)%mu*evolt
     893              :       END DO
     894              : 
     895          202 :       CALL timestop(handle)
     896              : 
     897          202 :    END SUBROUTINE make_mo_eig
     898              : 
     899              : END MODULE qs_mo_methods
        

Generated by: LCOV version 2.0-1