LCOV - code coverage report
Current view: top level - src - qs_ot_eigensolver.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:b310db4) Lines: 90.9 % 297 270
Test Date: 2026-10-23 01:10:43 Functions: 100.0 % 3 3

            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 an eigen-space solver for the generalised symmetric eigenvalue problem
      10              : !>      for sparse matrices, needing only multiplications
      11              : !> \author Joost VandeVondele (25.08.2002)
      12              : ! **************************************************************************************************
      13              : MODULE qs_ot_eigensolver
      14              :    USE cp_cfm_basic_linalg,             ONLY: cp_cfm_gemm
      15              :    USE cp_cfm_diag,                     ONLY: cp_cfm_heevd
      16              :    USE cp_cfm_types,                    ONLY: cp_cfm_create,&
      17              :                                               cp_cfm_release,&
      18              :                                               cp_cfm_to_fm,&
      19              :                                               cp_cfm_type,&
      20              :                                               cp_fm_to_cfm
      21              :    USE cp_dbcsr_api,                    ONLY: &
      22              :         dbcsr_add, dbcsr_copy, dbcsr_init_p, dbcsr_multiply, dbcsr_p_type, dbcsr_release_p, &
      23              :         dbcsr_scale, dbcsr_set, dbcsr_type, dbcsr_type_no_symmetry
      24              :    USE cp_dbcsr_cholesky,               ONLY: cp_dbcsr_cholesky_decompose,&
      25              :                                               cp_dbcsr_cholesky_invert
      26              :    USE cp_dbcsr_contrib,                ONLY: dbcsr_dot
      27              :    USE cp_dbcsr_operations,             ONLY: copy_dbcsr_to_fm,&
      28              :                                               copy_fm_to_dbcsr,&
      29              :                                               cp_dbcsr_m_by_n_from_row_template,&
      30              :                                               cp_dbcsr_m_by_n_from_template,&
      31              :                                               cp_dbcsr_sm_fm_multiply,&
      32              :                                               cp_fm_to_dbcsr_row_template,&
      33              :                                               dbcsr_copy_columns_hack
      34              :    USE cp_fm_types,                     ONLY: cp_fm_create,&
      35              :                                               cp_fm_get_info,&
      36              :                                               cp_fm_release,&
      37              :                                               cp_fm_type
      38              :    USE cp_log_handling,                 ONLY: cp_logger_get_default_io_unit
      39              :    USE input_constants,                 ONLY: ot_precond_fermi_low_rank,&
      40              :                                               ot_precond_full_all,&
      41              :                                               ot_precond_full_all_covariant,&
      42              :                                               ot_precond_full_kinetic,&
      43              :                                               ot_precond_full_single,&
      44              :                                               ot_precond_full_single_inverse,&
      45              :                                               ot_precond_none,&
      46              :                                               ot_precond_s_inverse
      47              :    USE kinds,                           ONLY: dp
      48              :    USE mathconstants,                   ONLY: z_one,&
      49              :                                               z_zero
      50              :    USE preconditioner,                  ONLY: make_preconditioner_complex_fermi_low_rank,&
      51              :                                               make_preconditioner_complex_full_all,&
      52              :                                               make_preconditioner_complex_full_all_covariant,&
      53              :                                               make_preconditioner_complex_full_kinetic,&
      54              :                                               make_preconditioner_complex_full_s_inverse,&
      55              :                                               make_preconditioner_complex_full_single,&
      56              :                                               make_preconditioner_complex_full_single_inverse
      57              :    USE preconditioner_types,            ONLY: destroy_preconditioner,&
      58              :                                               init_preconditioner,&
      59              :                                               preconditioner_in_use,&
      60              :                                               preconditioner_type
      61              :    USE qs_mo_methods,                   ONLY: make_basis_sv
      62              :    USE qs_mo_types,                     ONLY: mo_set_type
      63              :    USE qs_ot,                           ONLY: qs_ot_get_orbitals,&
      64              :                                               qs_ot_get_orbitals_complex,&
      65              :                                               qs_ot_get_orbitals_ref,&
      66              :                                               qs_ot_get_orbitals_ref_complex,&
      67              :                                               qs_ot_get_p,&
      68              :                                               qs_ot_new_preconditioner,&
      69              :                                               qs_ot_prepare_complex_tangent_metric
      70              :    USE qs_ot_minimizer,                 ONLY: ot_mini
      71              :    USE qs_ot_types,                     ONLY: qs_ot_allocate,&
      72              :                                               qs_ot_allocate_complex_state,&
      73              :                                               qs_ot_destroy,&
      74              :                                               qs_ot_init,&
      75              :                                               qs_ot_settings_init,&
      76              :                                               qs_ot_settings_type,&
      77              :                                               qs_ot_type
      78              : #include "./base/base_uses.f90"
      79              : 
      80              :    IMPLICIT NONE
      81              :    PRIVATE
      82              : 
      83              : ! *** Global parameters ***
      84              : 
      85              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_ot_eigensolver'
      86              : 
      87              : ! *** Public subroutines ***
      88              : 
      89              :    PUBLIC :: ot_eigensolver, ot_eigensolver_complex
      90              : 
      91              : CONTAINS
      92              : 
      93              : ! on input c contains the initial guess (should not be zero !)
      94              : ! on output c spans the subspace
      95              : ! **************************************************************************************************
      96              : !> \brief ...
      97              : !> \param matrix_h ...
      98              : !> \param matrix_s ...
      99              : !> \param matrix_orthogonal_space_fm ...
     100              : !> \param matrix_c_fm ...
     101              : !> \param preconditioner ...
     102              : !> \param eps_gradient ...
     103              : !> \param iter_max ...
     104              : !> \param size_ortho_space ...
     105              : !> \param silent ...
     106              : !> \param ot_settings ...
     107              : ! **************************************************************************************************
     108         1060 :    SUBROUTINE ot_eigensolver(matrix_h, matrix_s, matrix_orthogonal_space_fm, &
     109              :                              matrix_c_fm, preconditioner, eps_gradient, &
     110              :                              iter_max, size_ortho_space, silent, ot_settings)
     111              : 
     112              :       TYPE(dbcsr_type), POINTER                          :: matrix_h, matrix_s
     113              :       TYPE(cp_fm_type), INTENT(IN), OPTIONAL             :: matrix_orthogonal_space_fm
     114              :       TYPE(cp_fm_type), INTENT(INOUT)                    :: matrix_c_fm
     115              :       TYPE(preconditioner_type), OPTIONAL, POINTER       :: preconditioner
     116              :       REAL(KIND=dp)                                      :: eps_gradient
     117              :       INTEGER, INTENT(IN)                                :: iter_max
     118              :       INTEGER, INTENT(IN), OPTIONAL                      :: size_ortho_space
     119              :       LOGICAL, INTENT(IN), OPTIONAL                      :: silent
     120              :       TYPE(qs_ot_settings_type), INTENT(IN), OPTIONAL    :: ot_settings
     121              : 
     122              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'ot_eigensolver'
     123              :       INTEGER, PARAMETER                                 :: max_iter_inner_loop = 40
     124              :       REAL(KIND=dp), PARAMETER                           :: rone = 1.0_dp, rzero = 0.0_dp
     125              : 
     126              :       INTEGER                                            :: handle, ieigensolver, iter_total, k, n, &
     127              :                                                             ortho_k, ortho_space_k, output_unit
     128              :       LOGICAL                                            :: energy_only, my_silent, ortho, &
     129              :                                                             ref_algorithm
     130              :       REAL(KIND=dp)                                      :: delta, energy
     131          530 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_hc
     132              :       TYPE(dbcsr_type), POINTER                          :: matrix_buf1_ortho, matrix_buf2_ortho, &
     133              :                                                             matrix_c, matrix_orthogonal_space, &
     134              :                                                             matrix_os_ortho, matrix_s_ortho
     135          530 :       TYPE(qs_ot_type), DIMENSION(:), POINTER            :: qs_ot_env
     136              : 
     137          530 :       CALL timeset(routineN, handle)
     138              : 
     139          530 :       output_unit = cp_logger_get_default_io_unit()
     140              : 
     141          530 :       IF (PRESENT(silent)) THEN
     142          254 :          my_silent = silent
     143              :       ELSE
     144              :          my_silent = .FALSE.
     145              :       END IF
     146              : 
     147          530 :       NULLIFY (matrix_c) ! fm->dbcsr
     148              : 
     149          530 :       CALL cp_fm_get_info(matrix_c_fm, nrow_global=n, ncol_global=k) ! fm->dbcsr
     150          530 :       ALLOCATE (matrix_c)
     151          530 :       ref_algorithm = .FALSE.
     152          530 :       IF (PRESENT(ot_settings)) ref_algorithm = ot_settings%ot_algorithm == "REF"
     153          250 :       IF (ref_algorithm) THEN
     154           24 :          CALL dbcsr_init_p(matrix_c)
     155              :          CALL cp_dbcsr_m_by_n_from_row_template(matrix_c, template=matrix_h, n=k, &
     156           24 :                                                 sym=dbcsr_type_no_symmetry)
     157           24 :          CALL copy_fm_to_dbcsr(matrix_c_fm, matrix_c)
     158              :       ELSE
     159          506 :          CALL cp_fm_to_dbcsr_row_template(matrix_c, fm_in=matrix_c_fm, template=matrix_h)
     160              :       END IF
     161              : 
     162          530 :       iter_total = 0
     163              : 
     164              :       outer_scf: DO
     165              : 
     166              :          NULLIFY (qs_ot_env)
     167              : 
     168          712 :          NULLIFY (matrix_s_ortho)
     169          712 :          NULLIFY (matrix_os_ortho)
     170          712 :          NULLIFY (matrix_buf1_ortho)
     171          712 :          NULLIFY (matrix_buf2_ortho)
     172          712 :          NULLIFY (matrix_orthogonal_space)
     173              : 
     174       117480 :          ALLOCATE (qs_ot_env(1))
     175         1424 :          ALLOCATE (matrix_hc(1))
     176          712 :          NULLIFY (matrix_hc(1)%matrix)
     177          712 :          CALL dbcsr_init_p(matrix_hc(1)%matrix)
     178              : 
     179          712 :          ortho = .FALSE.
     180          712 :          IF (PRESENT(matrix_orthogonal_space_fm)) ortho = .TRUE.
     181              : 
     182              :          ! decide settings
     183          712 :          IF (PRESENT(ot_settings)) THEN
     184          262 :             qs_ot_env(1)%settings = ot_settings
     185              :          ELSE
     186          450 :             CALL qs_ot_settings_init(qs_ot_env(1)%settings)
     187              :             ! overwrite defaults
     188          450 :             qs_ot_env(1)%settings%ds_min = 0.10_dp
     189              :          END IF
     190              : 
     191          712 :          IF (ortho) THEN
     192          450 :             ALLOCATE (matrix_orthogonal_space)
     193          450 :             CALL cp_fm_to_dbcsr_row_template(matrix_orthogonal_space, fm_in=matrix_orthogonal_space_fm, template=matrix_h)
     194          450 :             CALL cp_fm_get_info(matrix_orthogonal_space_fm, ncol_global=ortho_space_k)
     195              : 
     196          450 :             IF (PRESENT(size_ortho_space)) ortho_space_k = size_ortho_space
     197          450 :             ortho_k = ortho_space_k + k
     198              :          ELSE
     199          262 :             ortho_k = k
     200              :          END IF
     201              : 
     202              :          ! allocate
     203          712 :          CALL qs_ot_allocate(qs_ot_env(1), matrix_s, matrix_c_fm%matrix_struct, ortho_k=ortho_k)
     204          712 :          IF (ref_algorithm) THEN
     205           30 :             CALL dbcsr_copy(matrix_hc(1)%matrix, qs_ot_env(1)%matrix_x, 'matrix_hc')
     206              :          ELSE
     207          682 :             CALL dbcsr_copy(matrix_hc(1)%matrix, matrix_c, 'matrix_hc')
     208              :          END IF
     209              : 
     210          712 :          IF (ortho) THEN
     211              :             ! construct an initial guess that is orthogonal to matrix_orthogonal_space
     212              : 
     213          450 :             CALL dbcsr_init_p(matrix_s_ortho)
     214          450 :             CALL dbcsr_copy(matrix_s_ortho, matrix_orthogonal_space, name="matrix_s_ortho")
     215              : 
     216          450 :             CALL dbcsr_init_p(matrix_os_ortho)
     217              :             CALL cp_dbcsr_m_by_n_from_template(matrix_os_ortho, template=matrix_h, m=ortho_space_k, n=ortho_space_k, &
     218          450 :                                                sym=dbcsr_type_no_symmetry)
     219              : 
     220          450 :             CALL dbcsr_init_p(matrix_buf1_ortho)
     221              :             CALL cp_dbcsr_m_by_n_from_template(matrix_buf1_ortho, template=matrix_h, m=ortho_space_k, n=k, &
     222          450 :                                                sym=dbcsr_type_no_symmetry)
     223              : 
     224          450 :             CALL dbcsr_init_p(matrix_buf2_ortho)
     225              :             CALL cp_dbcsr_m_by_n_from_template(matrix_buf2_ortho, template=matrix_h, m=ortho_space_k, n=k, &
     226          450 :                                                sym=dbcsr_type_no_symmetry)
     227              : 
     228              :             CALL dbcsr_multiply('N', 'N', 1.0_dp, matrix_s, matrix_orthogonal_space, &
     229          450 :                                 0.0_dp, matrix_s_ortho)
     230              :             CALL dbcsr_multiply('T', 'N', rone, matrix_s_ortho, matrix_s_ortho, &
     231          450 :                                 rzero, matrix_os_ortho)
     232              : 
     233              :             CALL cp_dbcsr_cholesky_decompose(matrix_os_ortho, &
     234          450 :                                              para_env=qs_ot_env(1)%para_env, blacs_env=qs_ot_env(1)%blacs_env)
     235              :             CALL cp_dbcsr_cholesky_invert(matrix_os_ortho, &
     236              :                                           para_env=qs_ot_env(1)%para_env, blacs_env=qs_ot_env(1)%blacs_env, &
     237          450 :                                           uplo_to_full=.TRUE.)
     238              : 
     239              :             CALL dbcsr_multiply('T', 'N', rone, matrix_s_ortho, matrix_c, &
     240          450 :                                 rzero, matrix_buf1_ortho)
     241              :             CALL dbcsr_multiply('N', 'N', rone, matrix_os_ortho, matrix_buf1_ortho, &
     242          450 :                                 rzero, matrix_buf2_ortho)
     243              :             CALL dbcsr_multiply('N', 'N', -rone, matrix_s_ortho, matrix_buf2_ortho, &
     244          450 :                                 rone, matrix_c)
     245              : 
     246              :             ! make matrix_c0 an orthogonal basis, matrix_c contains sc0
     247          450 :             CALL dbcsr_copy(qs_ot_env(1)%matrix_c0, matrix_c)
     248              :             CALL dbcsr_multiply('N', 'N', 1.0_dp, matrix_s, qs_ot_env(1)%matrix_c0, &
     249          450 :                                 0.0_dp, matrix_c)
     250              : 
     251              :             CALL make_basis_sv(qs_ot_env(1)%matrix_c0, k, matrix_c, &
     252          450 :                                qs_ot_env(1)%para_env, qs_ot_env(1)%blacs_env)
     253              : 
     254              :             ! copy sc0 and matrix_s_ortho in qs_ot_env(1)%matrix_sc0
     255              :             !CALL dbcsr_copy_columns(qs_ot_env(1)%matrix_sc0,matrix_s_ortho,ortho_space_k,1,1)
     256              :             CALL dbcsr_copy_columns_hack(qs_ot_env(1)%matrix_sc0, matrix_s_ortho, ortho_space_k, 1, 1, &
     257          450 :                                          para_env=qs_ot_env(1)%para_env, blacs_env=qs_ot_env(1)%blacs_env)
     258              :             !CALL dbcsr_copy_columns(qs_ot_env(1)%matrix_sc0,matrix_c,k,1,ortho_space_k+1)
     259              :             CALL dbcsr_copy_columns_hack(qs_ot_env(1)%matrix_sc0, matrix_c, k, 1, ortho_space_k + 1, &
     260          450 :                                          para_env=qs_ot_env(1)%para_env, blacs_env=qs_ot_env(1)%blacs_env)
     261              : 
     262          450 :             CALL dbcsr_release_p(matrix_buf1_ortho)
     263          450 :             CALL dbcsr_release_p(matrix_buf2_ortho)
     264          450 :             CALL dbcsr_release_p(matrix_os_ortho)
     265          450 :             CALL dbcsr_release_p(matrix_s_ortho)
     266              : 
     267              :          ELSE
     268              : 
     269              :             ! set c0,sc0
     270          262 :             CALL dbcsr_copy(qs_ot_env(1)%matrix_c0, matrix_c)
     271              :             CALL dbcsr_multiply('N', 'N', 1.0_dp, matrix_s, qs_ot_env(1)%matrix_c0, &
     272          262 :                                 0.0_dp, qs_ot_env(1)%matrix_sc0)
     273              : 
     274              :             CALL make_basis_sv(qs_ot_env(1)%matrix_c0, k, qs_ot_env(1)%matrix_sc0, &
     275          262 :                                qs_ot_env(1)%para_env, qs_ot_env(1)%blacs_env)
     276              :          END IF
     277              : 
     278              :          ! init
     279          712 :          CALL qs_ot_init(qs_ot_env(1))
     280          712 :          energy_only = qs_ot_env(1)%energy_only
     281              : 
     282          682 :          SELECT CASE (qs_ot_env(1)%settings%ot_algorithm)
     283              :          CASE ("TOD")
     284          682 :             CALL dbcsr_set(qs_ot_env(1)%matrix_x, 0.0_dp)
     285          682 :             CALL dbcsr_set(qs_ot_env(1)%matrix_sx, 0.0_dp)
     286          682 :             CALL qs_ot_get_p(qs_ot_env(1)%matrix_x, qs_ot_env(1)%matrix_sx, qs_ot_env(1))
     287          682 :             CALL qs_ot_get_orbitals(matrix_c, qs_ot_env(1)%matrix_x, qs_ot_env(1))
     288              :          CASE ("REF")
     289           30 :             CALL dbcsr_copy(qs_ot_env(1)%matrix_x, qs_ot_env(1)%matrix_c0)
     290           30 :             CALL dbcsr_copy(qs_ot_env(1)%matrix_sx, qs_ot_env(1)%matrix_sc0)
     291           30 :             CALL dbcsr_copy(matrix_c, qs_ot_env(1)%matrix_c0)
     292              :          CASE DEFAULT
     293          712 :             CPABORT("OT eigensolver supports ALGORITHM STRICT or IRAC")
     294              :          END SELECT
     295              : 
     296              :          ! if present preconditioner, use it
     297              : 
     298          712 :          IF (PRESENT(preconditioner)) THEN
     299          712 :             IF (ASSOCIATED(preconditioner)) THEN
     300          462 :                IF (preconditioner_in_use(preconditioner)) THEN
     301          462 :                   CALL qs_ot_new_preconditioner(qs_ot_env(1), preconditioner)
     302              :                ELSE
     303              :                   ! we should presumably make one
     304              :                END IF
     305              :             END IF
     306              :          END IF
     307              : 
     308              :          ! *** Eigensolver loop ***
     309              :          ieigensolver = 0
     310        12586 :          eigensolver_loop: DO
     311              : 
     312        12586 :             ieigensolver = ieigensolver + 1
     313        12586 :             iter_total = iter_total + 1
     314              : 
     315              :             ! the energy is cHc, the gradient is 2*H*c
     316              :             CALL dbcsr_multiply('N', 'N', 1.0_dp, matrix_h, matrix_c, &
     317        12586 :                                 0.0_dp, matrix_hc(1)%matrix)
     318        12586 :             CALL dbcsr_dot(matrix_c, matrix_hc(1)%matrix, energy)
     319        12586 :             IF (.NOT. energy_only) THEN
     320         6684 :                CALL dbcsr_scale(matrix_hc(1)%matrix, 2.0_dp)
     321              :             END IF
     322              : 
     323        12586 :             qs_ot_env(1)%etotal = energy
     324        12586 :             CALL ot_mini(qs_ot_env, matrix_hc)
     325        12586 :             delta = qs_ot_env(1)%delta
     326        12586 :             energy_only = qs_ot_env(1)%energy_only
     327              : 
     328        12042 :             SELECT CASE (qs_ot_env(1)%settings%ot_algorithm)
     329              :             CASE ("TOD")
     330              :                CALL dbcsr_multiply('N', 'N', 1.0_dp, matrix_s, qs_ot_env(1)%matrix_x, &
     331        12042 :                                    0.0_dp, qs_ot_env(1)%matrix_sx)
     332        12042 :                CALL qs_ot_get_p(qs_ot_env(1)%matrix_x, qs_ot_env(1)%matrix_sx, qs_ot_env(1))
     333        12042 :                CALL qs_ot_get_orbitals(matrix_c, qs_ot_env(1)%matrix_x, qs_ot_env(1))
     334              :             CASE ("REF")
     335              :                CALL qs_ot_get_orbitals_ref(matrix_c, matrix_s, qs_ot_env(1)%matrix_x, &
     336              :                                            qs_ot_env(1)%matrix_sx, qs_ot_env(1)%matrix_gx_old, &
     337        12586 :                                            qs_ot_env(1)%matrix_dx, qs_ot_env(1), qs_ot_env(1))
     338              :             END SELECT
     339              : 
     340              :             ! exit on convergence or if maximum of inner loop  cycles is reached
     341        12586 :             IF (delta < eps_gradient .OR. ieigensolver >= max_iter_inner_loop) EXIT eigensolver_loop
     342              :             ! exit if total number of steps is reached, but not during a line search step
     343        12586 :             IF (iter_total >= iter_max .AND. qs_ot_env(1)%OT_METHOD_FULL /= "OT LS") EXIT eigensolver_loop
     344              : 
     345              :          END DO eigensolver_loop
     346              : 
     347          712 :          CALL qs_ot_destroy(qs_ot_env(1))
     348          712 :          DEALLOCATE (qs_ot_env)
     349          712 :          CALL dbcsr_release_p(matrix_hc(1)%matrix)
     350          712 :          DEALLOCATE (matrix_hc)
     351          712 :          CALL dbcsr_release_p(matrix_orthogonal_space)
     352              : 
     353          712 :          IF (delta < eps_gradient) THEN
     354          384 :             IF ((output_unit > 0) .AND. .NOT. my_silent) THEN
     355              :                WRITE (UNIT=output_unit, FMT="(T2,A,I0,A)") &
     356          144 :                   "OT| Eigensolver reached convergence in ", iter_total, " iterations"
     357              :             END IF
     358              :             EXIT outer_scf
     359              :          END IF
     360          328 :          IF (iter_total >= iter_max) THEN
     361          146 :             IF (output_unit > 0) THEN
     362           73 :                IF (my_silent) THEN
     363           73 :                   WRITE (output_unit, "(A,T60,E20.10)") "  WARNING OT eigensolver did not converge: current gradient", delta
     364              :                ELSE
     365            0 :                   WRITE (output_unit, *) "WARNING : did not converge in ot_eigensolver"
     366            0 :                   WRITE (output_unit, *) "number of iterations ", iter_total, " exceeded maximum"
     367            0 :                   WRITE (output_unit, *) "current gradient / target gradient", delta, " / ", eps_gradient
     368              :                END IF
     369              :             END IF
     370              :             EXIT outer_scf
     371              :          END IF
     372              : 
     373              :       END DO outer_scf
     374              : 
     375          530 :       CALL copy_dbcsr_to_fm(matrix_c, matrix_c_fm) ! fm->dbcsr
     376          530 :       CALL dbcsr_release_p(matrix_c) ! fm->dbcsr
     377              : 
     378          530 :       CALL timestop(handle)
     379              : 
     380          530 :    END SUBROUTINE ot_eigensolver
     381              : 
     382              : ! **************************************************************************************************
     383              : !> \brief solve a fixed complex Hermitian generalized eigenproblem by OT
     384              : !> \param matrix_h real part of H(k)
     385              : !> \param matrix_h_im imaginary part of H(k)
     386              : !> \param matrix_s real part of S(k)
     387              : !> \param matrix_s_im imaginary part of S(k)
     388              : !> \param matrix_c_cfm complex orbital coefficients
     389              : !> \param preconditioner optional complex k-point preconditioner
     390              : !> \param eps_gradient requested OT gradient accuracy
     391              : !> \param iter_max maximum number of OT iterations
     392              : !> \param eigenvalues ...
     393              : !> \param silent suppress successful convergence output
     394              : !> \param ot_settings OT algorithm and minimizer settings
     395              : !> \param matrix_t ...
     396              : !> \param matrix_t_im ...
     397              : !> \param mo_set ...
     398              : ! **************************************************************************************************
     399          860 :    SUBROUTINE ot_eigensolver_complex(matrix_h, matrix_h_im, matrix_s, matrix_s_im, &
     400              :                                      matrix_c_cfm, preconditioner, &
     401          172 :                                      eps_gradient, iter_max, eigenvalues, silent, ot_settings, &
     402              :                                      matrix_t, matrix_t_im, mo_set)
     403              : 
     404              :       TYPE(dbcsr_type), POINTER                          :: matrix_h, matrix_h_im, matrix_s, &
     405              :                                                             matrix_s_im
     406              :       TYPE(cp_cfm_type), INTENT(INOUT)                   :: matrix_c_cfm
     407              :       TYPE(preconditioner_type), OPTIONAL, POINTER       :: preconditioner
     408              :       REAL(KIND=dp), INTENT(IN)                          :: eps_gradient
     409              :       INTEGER, INTENT(IN)                                :: iter_max
     410              :       REAL(KIND=dp), DIMENSION(:), INTENT(OUT), OPTIONAL :: eigenvalues
     411              :       LOGICAL, INTENT(IN), OPTIONAL                      :: silent
     412              :       TYPE(qs_ot_settings_type), INTENT(IN), OPTIONAL    :: ot_settings
     413              :       TYPE(dbcsr_type), OPTIONAL, POINTER                :: matrix_t, matrix_t_im
     414              :       TYPE(mo_set_type), INTENT(IN), OPTIONAL            :: mo_set
     415              : 
     416              :       CHARACTER(len=*), PARAMETER :: routineN = 'ot_eigensolver_complex'
     417              :       INTEGER, PARAMETER                                 :: max_iter_inner_loop = 40
     418              : 
     419              :       INTEGER                                            :: handle, ieigensolver, iter_total, k, n, &
     420              :                                                             output_unit
     421              :       LOGICAL                                            :: energy_only, my_silent, &
     422              :                                                             preconditioner_rejected
     423              :       REAL(KIND=dp)                                      :: delta, energy_im, energy_re
     424              :       TYPE(cp_fm_type)                                   :: matrix_c_fm, matrix_c_fm_im
     425          172 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_hc, matrix_hc_im
     426              :       TYPE(dbcsr_type), POINTER                          :: matrix_c, matrix_c_im, matrix_tmp
     427              :       TYPE(preconditioner_type), POINTER                 :: local_preconditioner
     428          172 :       TYPE(qs_ot_type), DIMENSION(:), POINTER            :: qs_ot_env
     429              : 
     430          172 :       CALL timeset(routineN, handle)
     431          172 :       output_unit = cp_logger_get_default_io_unit()
     432          172 :       my_silent = .FALSE.
     433          172 :       IF (PRESENT(silent)) my_silent = silent
     434          172 :       NULLIFY (local_preconditioner)
     435              : 
     436          172 :       CALL cp_fm_create(matrix_c_fm, matrix_c_cfm%matrix_struct)
     437          172 :       CALL cp_fm_create(matrix_c_fm_im, matrix_c_cfm%matrix_struct)
     438          172 :       CALL cp_cfm_to_fm(matrix_c_cfm, matrix_c_fm, matrix_c_fm_im)
     439          172 :       CALL cp_fm_get_info(matrix_c_fm, nrow_global=n, ncol_global=k)
     440          172 :       CPASSERT(n > 0 .AND. k > 0)
     441          172 :       ALLOCATE (matrix_c, matrix_c_im, matrix_tmp)
     442          172 :       CALL dbcsr_init_p(matrix_c)
     443              :       CALL cp_dbcsr_m_by_n_from_row_template(matrix_c, template=matrix_h, n=k, &
     444          172 :                                              sym=dbcsr_type_no_symmetry)
     445          172 :       CALL dbcsr_init_p(matrix_c_im)
     446              :       CALL cp_dbcsr_m_by_n_from_row_template(matrix_c_im, template=matrix_h, n=k, &
     447          172 :                                              sym=dbcsr_type_no_symmetry)
     448          172 :       CALL dbcsr_init_p(matrix_tmp)
     449              :       CALL cp_dbcsr_m_by_n_from_row_template(matrix_tmp, template=matrix_h, n=k, &
     450          172 :                                              sym=dbcsr_type_no_symmetry)
     451          172 :       CALL copy_fm_to_dbcsr(matrix_c_fm, matrix_c)
     452          172 :       CALL copy_fm_to_dbcsr(matrix_c_fm_im, matrix_c_im)
     453              : 
     454          172 :       iter_total = 0
     455              :       outer_scf: DO
     456        29392 :          ALLOCATE (qs_ot_env(1), matrix_hc(1), matrix_hc_im(1))
     457          176 :          NULLIFY (matrix_hc(1)%matrix, matrix_hc_im(1)%matrix)
     458              : 
     459          176 :          IF (PRESENT(ot_settings)) THEN
     460          176 :             qs_ot_env(1)%settings = ot_settings
     461              :          ELSE
     462            0 :             CALL qs_ot_settings_init(qs_ot_env(1)%settings)
     463            0 :             qs_ot_env(1)%settings%ds_min = 0.10_dp
     464              :          END IF
     465              : 
     466          176 :          CALL qs_ot_allocate(qs_ot_env(1), matrix_s, matrix_c_fm%matrix_struct)
     467          176 :          CALL qs_ot_allocate_complex_state(qs_ot_env(1), matrix_s)
     468          176 :          CALL dbcsr_init_p(matrix_hc(1)%matrix)
     469          176 :          CALL dbcsr_copy(matrix_hc(1)%matrix, qs_ot_env(1)%matrix_x, 'matrix_hc')
     470          176 :          CALL dbcsr_init_p(matrix_hc_im(1)%matrix)
     471          176 :          CALL dbcsr_copy(matrix_hc_im(1)%matrix, qs_ot_env(1)%matrix_x_im, 'matrix_hc_im')
     472              : 
     473          176 :          CALL dbcsr_copy(qs_ot_env(1)%matrix_c0, matrix_c)
     474          176 :          CALL dbcsr_copy(qs_ot_env(1)%matrix_c0_im, matrix_c_im)
     475              :          CALL dbcsr_multiply('N', 'N', 1.0_dp, matrix_s, matrix_c, &
     476          176 :                              0.0_dp, qs_ot_env(1)%matrix_sc0)
     477              :          CALL dbcsr_multiply('N', 'N', 1.0_dp, matrix_s_im, matrix_c_im, &
     478          176 :                              0.0_dp, matrix_tmp)
     479              :          CALL dbcsr_add(qs_ot_env(1)%matrix_sc0, matrix_tmp, &
     480          176 :                         alpha_scalar=1.0_dp, beta_scalar=-1.0_dp)
     481              :          CALL dbcsr_multiply('N', 'N', 1.0_dp, matrix_s, matrix_c_im, &
     482          176 :                              0.0_dp, qs_ot_env(1)%matrix_sc0_im)
     483              :          CALL dbcsr_multiply('N', 'N', 1.0_dp, matrix_s_im, matrix_c, &
     484          176 :                              0.0_dp, matrix_tmp)
     485              :          CALL dbcsr_add(qs_ot_env(1)%matrix_sc0_im, matrix_tmp, &
     486          176 :                         alpha_scalar=1.0_dp, beta_scalar=1.0_dp)
     487              : 
     488          176 :          CALL qs_ot_init(qs_ot_env(1))
     489          176 :          energy_only = qs_ot_env(1)%energy_only
     490          100 :          SELECT CASE (qs_ot_env(1)%settings%ot_algorithm)
     491              :          CASE ('TOD')
     492          100 :             CALL dbcsr_set(qs_ot_env(1)%matrix_x, 0.0_dp)
     493          100 :             CALL dbcsr_set(qs_ot_env(1)%matrix_x_im, 0.0_dp)
     494          100 :             CALL dbcsr_set(qs_ot_env(1)%matrix_sx, 0.0_dp)
     495          100 :             CALL dbcsr_set(qs_ot_env(1)%matrix_sx_im, 0.0_dp)
     496              :             CALL qs_ot_get_orbitals_complex(matrix_c, matrix_c_im, matrix_s, matrix_s_im, &
     497          100 :                                             qs_ot_env(1))
     498              :          CASE ('REF')
     499           76 :             CALL dbcsr_copy(qs_ot_env(1)%matrix_x, qs_ot_env(1)%matrix_c0)
     500           76 :             CALL dbcsr_copy(qs_ot_env(1)%matrix_x_im, qs_ot_env(1)%matrix_c0_im)
     501           76 :             CALL dbcsr_copy(qs_ot_env(1)%matrix_sx, qs_ot_env(1)%matrix_sc0)
     502           76 :             CALL dbcsr_copy(qs_ot_env(1)%matrix_sx_im, qs_ot_env(1)%matrix_sc0_im)
     503              :             CALL qs_ot_get_orbitals_ref_complex(matrix_c, matrix_c_im, matrix_s, matrix_s_im, &
     504           76 :                                                 qs_ot_env(1), qs_ot_env(1))
     505              :          CASE DEFAULT
     506          176 :             CPABORT('Complex OT eigensolver supports ALGORITHM STRICT or IRAC')
     507              :          END SELECT
     508              : 
     509          176 :          IF (.NOT. PRESENT(preconditioner) .AND. .NOT. ASSOCIATED(local_preconditioner) .AND. &
     510              :              qs_ot_env(1)%settings%preconditioner_type /= ot_precond_none) THEN
     511          688 :             ALLOCATE (local_preconditioner)
     512          172 :             CALL init_preconditioner(local_preconditioner, qs_ot_env(1)%para_env, qs_ot_env(1)%blacs_env)
     513          212 :             SELECT CASE (qs_ot_env(1)%settings%preconditioner_type)
     514              :             CASE (ot_precond_fermi_low_rank)
     515              :                CALL make_preconditioner_complex_fermi_low_rank( &
     516              :                   local_preconditioner, qs_ot_env(1)%matrix_c0, qs_ot_env(1)%matrix_c0_im, &
     517              :                   matrix_h, matrix_h_im, matrix_s, matrix_s_im, &
     518              :                   qs_ot_env(1)%settings%energy_gap, &
     519              :                   qs_ot_env(1)%settings%fermi_low_rank_max_rank, &
     520           40 :                   qs_ot_env(1)%settings%precond_solver_type)
     521              :             CASE (ot_precond_full_all, ot_precond_full_all_covariant)
     522           92 :                IF (qs_ot_env(1)%settings%ot_algorithm == 'TOD') THEN
     523              :                   ! State-selective FULL_ALL models can destabilize the finite STRICT fixed-H chart
     524              :                   ! even when the tangent metric is positive. Retain a well-defined eigensolver with
     525              :                   ! their S^-1 base; IRAC can use the complete state-dependent inverse below.
     526              :                   CALL make_preconditioner_complex_full_s_inverse( &
     527              :                      local_preconditioner, matrix_s, matrix_s_im, &
     528           16 :                      qs_ot_env(1)%settings%precond_solver_type)
     529           76 :                ELSE IF (qs_ot_env(1)%settings%preconditioner_type == ot_precond_full_all) THEN
     530           36 :                   IF (.NOT. PRESENT(mo_set)) THEN
     531            0 :                      CPABORT('Complex FULL_ALL eigensolver preconditioning requires MO energy labels')
     532              :                   END IF
     533              :                   CALL make_preconditioner_complex_full_all( &
     534              :                      local_preconditioner, qs_ot_env(1)%matrix_c0, qs_ot_env(1)%matrix_c0_im, &
     535              :                      matrix_h, matrix_h_im, matrix_s, matrix_s_im, mo_set, &
     536           36 :                      qs_ot_env(1)%settings%energy_gap, qs_ot_env(1)%settings%precond_solver_type)
     537              :                ELSE
     538              :                   CALL make_preconditioner_complex_full_all_covariant( &
     539              :                      local_preconditioner, qs_ot_env(1)%matrix_c0, qs_ot_env(1)%matrix_c0_im, &
     540              :                      matrix_h, matrix_h_im, matrix_s, matrix_s_im, &
     541           40 :                      qs_ot_env(1)%settings%energy_gap, qs_ot_env(1)%settings%precond_solver_type)
     542              :                END IF
     543              :             CASE (ot_precond_full_single)
     544            0 :                IF (.NOT. PRESENT(mo_set)) THEN
     545            0 :                   CPABORT('Complex FULL_SINGLE eigensolver preconditioning requires MO energy labels')
     546              :                END IF
     547              :                CALL make_preconditioner_complex_full_single( &
     548              :                   local_preconditioner, matrix_h, matrix_h_im, matrix_s, matrix_s_im, mo_set, &
     549            0 :                   qs_ot_env(1)%settings%energy_gap, qs_ot_env(1)%settings%precond_solver_type)
     550              :             CASE (ot_precond_full_single_inverse)
     551              :                CALL make_preconditioner_complex_full_single_inverse( &
     552              :                   local_preconditioner, qs_ot_env(1)%matrix_c0, qs_ot_env(1)%matrix_c0_im, &
     553              :                   matrix_h, matrix_h_im, matrix_s, matrix_s_im, &
     554           40 :                   qs_ot_env(1)%settings%energy_gap, qs_ot_env(1)%settings%precond_solver_type)
     555              :             CASE (ot_precond_full_kinetic)
     556            0 :                IF (.NOT. PRESENT(matrix_t) .OR. .NOT. PRESENT(matrix_t_im)) THEN
     557            0 :                   CPABORT('Complex FULL_KINETIC eigensolver preconditioning requires T(k)')
     558              :                END IF
     559            0 :                IF (.NOT. ASSOCIATED(matrix_t) .OR. .NOT. ASSOCIATED(matrix_t_im)) THEN
     560            0 :                   CPABORT('Complex FULL_KINETIC eigensolver preconditioning requires T(k)')
     561              :                END IF
     562              :                CALL make_preconditioner_complex_full_kinetic( &
     563              :                   local_preconditioner, matrix_t, matrix_t_im, matrix_s, matrix_s_im, &
     564            0 :                   qs_ot_env(1)%settings%energy_gap, qs_ot_env(1)%settings%precond_solver_type)
     565              :             CASE (ot_precond_s_inverse)
     566              :                CALL make_preconditioner_complex_full_s_inverse( &
     567              :                   local_preconditioner, matrix_s, matrix_s_im, &
     568            0 :                   qs_ot_env(1)%settings%precond_solver_type)
     569              :             CASE DEFAULT
     570          172 :                CPABORT('Unsupported complex K-point OT eigensolver preconditioner')
     571              :             END SELECT
     572              :          END IF
     573              : 
     574          176 :          IF (PRESENT(preconditioner)) THEN
     575            0 :             IF (ASSOCIATED(preconditioner)) THEN
     576            0 :                IF (preconditioner_in_use(preconditioner)) THEN
     577            0 :                   CALL qs_ot_new_preconditioner(qs_ot_env(1), preconditioner)
     578              :                END IF
     579              :             END IF
     580          176 :          ELSE IF (ASSOCIATED(local_preconditioner)) THEN
     581          176 :             CALL qs_ot_new_preconditioner(qs_ot_env(1), local_preconditioner)
     582              :          END IF
     583              : 
     584          176 :          IF (qs_ot_env(1)%settings%ot_algorithm == 'TOD') THEN
     585          100 :             CALL qs_ot_prepare_complex_tangent_metric(qs_ot_env(1), preconditioner_rejected)
     586          100 :             IF (preconditioner_rejected .AND. ASSOCIATED(local_preconditioner)) THEN
     587            0 :                CALL destroy_preconditioner(local_preconditioner)
     588              :                CALL init_preconditioner(local_preconditioner, &
     589            0 :                                         qs_ot_env(1)%para_env, qs_ot_env(1)%blacs_env)
     590              :                CALL make_preconditioner_complex_full_s_inverse( &
     591              :                   local_preconditioner, matrix_s, matrix_s_im, &
     592            0 :                   qs_ot_env(1)%settings%precond_solver_type)
     593            0 :                CALL qs_ot_new_preconditioner(qs_ot_env(1), local_preconditioner)
     594            0 :                CALL qs_ot_prepare_complex_tangent_metric(qs_ot_env(1), preconditioner_rejected)
     595            0 :                CPASSERT(.NOT. preconditioner_rejected)
     596              :             END IF
     597              :          END IF
     598              : 
     599              :          ieigensolver = 0
     600         1144 :          eigensolver_loop: DO
     601          572 :             ieigensolver = ieigensolver + 1
     602          572 :             iter_total = iter_total + 1
     603              : 
     604              :             ! H*C = (Hre*Cre-Him*Cim) + i*(Hre*Cim+Him*Cre).
     605              :             CALL dbcsr_multiply('N', 'N', 1.0_dp, matrix_h, matrix_c, &
     606          572 :                                 0.0_dp, matrix_hc(1)%matrix)
     607              :             CALL dbcsr_multiply('N', 'N', 1.0_dp, matrix_h_im, matrix_c_im, &
     608          572 :                                 0.0_dp, matrix_tmp)
     609              :             CALL dbcsr_add(matrix_hc(1)%matrix, matrix_tmp, &
     610          572 :                            alpha_scalar=1.0_dp, beta_scalar=-1.0_dp)
     611              :             CALL dbcsr_multiply('N', 'N', 1.0_dp, matrix_h, matrix_c_im, &
     612          572 :                                 0.0_dp, matrix_hc_im(1)%matrix)
     613              :             CALL dbcsr_multiply('N', 'N', 1.0_dp, matrix_h_im, matrix_c, &
     614          572 :                                 0.0_dp, matrix_tmp)
     615              :             CALL dbcsr_add(matrix_hc_im(1)%matrix, matrix_tmp, &
     616          572 :                            alpha_scalar=1.0_dp, beta_scalar=1.0_dp)
     617              : 
     618          572 :             CALL dbcsr_dot(matrix_c, matrix_hc(1)%matrix, energy_re)
     619          572 :             CALL dbcsr_dot(matrix_c_im, matrix_hc_im(1)%matrix, energy_im)
     620          572 :             qs_ot_env(1)%etotal = energy_re + energy_im
     621          572 :             IF (.NOT. energy_only) THEN
     622          572 :                CALL dbcsr_scale(matrix_hc(1)%matrix, 2.0_dp)
     623          572 :                CALL dbcsr_scale(matrix_hc_im(1)%matrix, 2.0_dp)
     624              :             END IF
     625          572 :             CALL ot_mini(qs_ot_env, matrix_hc, matrix_hc_im=matrix_hc_im)
     626          572 :             delta = qs_ot_env(1)%delta
     627          572 :             energy_only = qs_ot_env(1)%energy_only
     628              : 
     629          426 :             SELECT CASE (qs_ot_env(1)%settings%ot_algorithm)
     630              :             CASE ('TOD')
     631              :                CALL qs_ot_get_orbitals_complex(matrix_c, matrix_c_im, matrix_s, matrix_s_im, &
     632          426 :                                                qs_ot_env(1))
     633              :             CASE ('REF')
     634              :                CALL qs_ot_get_orbitals_ref_complex(matrix_c, matrix_c_im, matrix_s, matrix_s_im, &
     635          572 :                                                    qs_ot_env(1), qs_ot_env(1))
     636              :             END SELECT
     637              : 
     638          572 :             IF (delta < eps_gradient .OR. ieigensolver >= max_iter_inner_loop) EXIT eigensolver_loop
     639          572 :             IF (iter_total >= iter_max .AND. qs_ot_env(1)%OT_METHOD_FULL /= 'OT LS') EXIT eigensolver_loop
     640              :          END DO eigensolver_loop
     641              : 
     642          176 :          CALL qs_ot_destroy(qs_ot_env(1))
     643          176 :          DEALLOCATE (qs_ot_env)
     644          176 :          CALL dbcsr_release_p(matrix_hc(1)%matrix)
     645          176 :          CALL dbcsr_release_p(matrix_hc_im(1)%matrix)
     646          176 :          DEALLOCATE (matrix_hc, matrix_hc_im)
     647              : 
     648          176 :          IF (delta < eps_gradient) THEN
     649          172 :             IF (output_unit > 0 .AND. .NOT. my_silent) THEN
     650              :                WRITE (UNIT=output_unit, FMT='(T2,A,I0,A)') &
     651            0 :                   'OT| Complex eigensolver reached convergence in ', iter_total, ' iterations'
     652              :             END IF
     653              :             EXIT outer_scf
     654              :          END IF
     655            4 :          IF (iter_total >= iter_max) THEN
     656            0 :             IF (output_unit > 0) THEN
     657              :                WRITE (output_unit, '(A,T60,E20.10)') &
     658            0 :                   '  WARNING complex OT eigensolver did not converge: current gradient', delta
     659              :             END IF
     660              :             EXIT outer_scf
     661              :          END IF
     662              :       END DO outer_scf
     663              : 
     664          172 :       CALL copy_dbcsr_to_fm(matrix_c, matrix_c_fm)
     665          172 :       CALL copy_dbcsr_to_fm(matrix_c_im, matrix_c_fm_im)
     666          172 :       IF (PRESENT(eigenvalues)) THEN
     667              :          CALL canonicalize_complex_subspace(matrix_h, matrix_h_im, matrix_c_fm, &
     668          172 :                                             matrix_c_fm_im, eigenvalues)
     669              :       END IF
     670          172 :       CALL cp_fm_to_cfm(matrix_c_fm, matrix_c_fm_im, matrix_c_cfm)
     671          172 :       CALL cp_fm_release(matrix_c_fm)
     672          172 :       CALL cp_fm_release(matrix_c_fm_im)
     673          172 :       CALL dbcsr_release_p(matrix_c)
     674          172 :       CALL dbcsr_release_p(matrix_c_im)
     675          172 :       CALL dbcsr_release_p(matrix_tmp)
     676          172 :       IF (ASSOCIATED(local_preconditioner)) THEN
     677          172 :          CALL destroy_preconditioner(local_preconditioner)
     678          172 :          DEALLOCATE (local_preconditioner)
     679              :       END IF
     680          172 :       CALL timestop(handle)
     681              : 
     682          172 :    END SUBROUTINE ot_eigensolver_complex
     683              : 
     684              : ! **************************************************************************************************
     685              : !> \brief diagonalize C^H H C and rotate a complex orthonormal orbital subspace
     686              : !> \param matrix_h ...
     687              : !> \param matrix_h_im ...
     688              : !> \param coeff_re ...
     689              : !> \param coeff_im ...
     690              : !> \param eigenvalues ...
     691              : ! **************************************************************************************************
     692          172 :    SUBROUTINE canonicalize_complex_subspace(matrix_h, matrix_h_im, coeff_re, coeff_im, eigenvalues)
     693              :       TYPE(dbcsr_type), POINTER                          :: matrix_h, matrix_h_im
     694              :       TYPE(cp_fm_type), INTENT(INOUT)                    :: coeff_re, coeff_im
     695              :       REAL(KIND=dp), DIMENSION(:), INTENT(OUT)           :: eigenvalues
     696              : 
     697              :       INTEGER                                            :: nao, nmo
     698              :       TYPE(cp_cfm_type)                                  :: coeff, eigenvectors, hblock, hc, rotated
     699              :       TYPE(cp_fm_type)                                   :: hc_im, hc_re
     700              : 
     701          172 :       CALL cp_fm_get_info(coeff_re, nrow_global=nao, ncol_global=nmo)
     702          172 :       CPASSERT(SIZE(eigenvalues) >= nmo)
     703          172 :       CALL cp_fm_create(hc_re, coeff_re%matrix_struct)
     704          172 :       CALL cp_fm_create(hc_im, coeff_re%matrix_struct)
     705          172 :       CALL cp_dbcsr_sm_fm_multiply(matrix_h, coeff_re, hc_re, nmo)
     706              :       CALL cp_dbcsr_sm_fm_multiply(matrix_h_im, coeff_im, hc_re, nmo, &
     707          172 :                                    alpha=-1.0_dp, beta=1.0_dp)
     708          172 :       CALL cp_dbcsr_sm_fm_multiply(matrix_h, coeff_im, hc_im, nmo)
     709              :       CALL cp_dbcsr_sm_fm_multiply(matrix_h_im, coeff_re, hc_im, nmo, &
     710          172 :                                    alpha=1.0_dp, beta=1.0_dp)
     711              : 
     712          172 :       CALL cp_cfm_create(coeff, coeff_re%matrix_struct)
     713          172 :       CALL cp_cfm_create(hc, coeff_re%matrix_struct)
     714          172 :       CALL cp_cfm_create(rotated, coeff_re%matrix_struct)
     715          172 :       CALL cp_cfm_create(hblock, coeff_re%matrix_struct, nrow=nmo, ncol=nmo)
     716          172 :       CALL cp_cfm_create(eigenvectors, coeff_re%matrix_struct, nrow=nmo, ncol=nmo)
     717          172 :       CALL cp_fm_to_cfm(coeff_re, coeff_im, coeff)
     718          172 :       CALL cp_fm_to_cfm(hc_re, hc_im, hc)
     719          172 :       CALL cp_cfm_gemm('C', 'N', nmo, nmo, nao, z_one, coeff, hc, z_zero, hblock)
     720          172 :       CALL cp_cfm_heevd(hblock, eigenvectors, eigenvalues(1:nmo))
     721          172 :       CALL cp_cfm_gemm('N', 'N', nao, nmo, nmo, z_one, coeff, eigenvectors, z_zero, rotated)
     722          172 :       CALL cp_cfm_to_fm(rotated, coeff_re, coeff_im)
     723              : 
     724          172 :       CALL cp_cfm_release(eigenvectors)
     725          172 :       CALL cp_cfm_release(hblock)
     726          172 :       CALL cp_cfm_release(rotated)
     727          172 :       CALL cp_cfm_release(hc)
     728          172 :       CALL cp_cfm_release(coeff)
     729          172 :       CALL cp_fm_release(hc_im)
     730          172 :       CALL cp_fm_release(hc_re)
     731          172 :    END SUBROUTINE canonicalize_complex_subspace
     732              : 
     733              : END MODULE qs_ot_eigensolver
        

Generated by: LCOV version 2.0-1