LCOV - code coverage report
Current view: top level - src - qs_tddfpt2_utils.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:936074a) Lines: 74.4 % 523 389
Test Date: 2025-12-04 06:27:48 Functions: 100.0 % 7 7

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2025 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : MODULE qs_tddfpt2_utils
       9              :    USE cell_types,                      ONLY: cell_type
      10              :    USE cp_array_utils,                  ONLY: cp_1d_r_p_type
      11              :    USE cp_blacs_env,                    ONLY: cp_blacs_env_type
      12              :    USE cp_control_types,                ONLY: dft_control_type,&
      13              :                                               tddfpt2_control_type
      14              :    USE cp_dbcsr_api,                    ONLY: dbcsr_add,&
      15              :                                               dbcsr_copy,&
      16              :                                               dbcsr_get_info,&
      17              :                                               dbcsr_init_p,&
      18              :                                               dbcsr_p_type,&
      19              :                                               dbcsr_type
      20              :    USE cp_dbcsr_operations,             ONLY: copy_dbcsr_to_fm,&
      21              :                                               cp_dbcsr_plus_fm_fm_t,&
      22              :                                               cp_dbcsr_sm_fm_multiply,&
      23              :                                               dbcsr_allocate_matrix_set
      24              :    USE cp_fm_basic_linalg,              ONLY: cp_fm_triangular_invert
      25              :    USE cp_fm_cholesky,                  ONLY: cp_fm_cholesky_decompose
      26              :    USE cp_fm_pool_types,                ONLY: cp_fm_pool_p_type,&
      27              :                                               fm_pool_create_fm
      28              :    USE cp_fm_struct,                    ONLY: cp_fm_struct_create,&
      29              :                                               cp_fm_struct_release,&
      30              :                                               cp_fm_struct_type
      31              :    USE cp_fm_types,                     ONLY: cp_fm_create,&
      32              :                                               cp_fm_get_info,&
      33              :                                               cp_fm_release,&
      34              :                                               cp_fm_set_all,&
      35              :                                               cp_fm_to_fm,&
      36              :                                               cp_fm_to_fm_submat,&
      37              :                                               cp_fm_type
      38              :    USE cp_log_handling,                 ONLY: cp_get_default_logger,&
      39              :                                               cp_logger_get_default_io_unit,&
      40              :                                               cp_logger_type
      41              :    USE exstates_types,                  ONLY: excited_energy_type
      42              :    USE input_constants,                 ONLY: &
      43              :         cholesky_dbcsr, cholesky_inverse, cholesky_off, cholesky_restore, no_sf_tddfpt, oe_gllb, &
      44              :         oe_lb, oe_none, oe_saop, oe_shift
      45              :    USE input_section_types,             ONLY: section_vals_create,&
      46              :                                               section_vals_get,&
      47              :                                               section_vals_get_subs_vals,&
      48              :                                               section_vals_release,&
      49              :                                               section_vals_retain,&
      50              :                                               section_vals_set_subs_vals,&
      51              :                                               section_vals_type,&
      52              :                                               section_vals_val_get
      53              :    USE kinds,                           ONLY: dp,&
      54              :                                               int_8
      55              :    USE message_passing,                 ONLY: mp_para_env_type
      56              :    USE parallel_gemm_api,               ONLY: parallel_gemm
      57              :    USE physcon,                         ONLY: evolt
      58              :    USE qs_environment_types,            ONLY: get_qs_env,&
      59              :                                               qs_environment_type
      60              :    USE qs_ks_methods,                   ONLY: qs_ks_build_kohn_sham_matrix
      61              :    USE qs_ks_types,                     ONLY: qs_ks_env_type,&
      62              :                                               set_ks_env
      63              :    USE qs_mo_types,                     ONLY: allocate_mo_set,&
      64              :                                               deallocate_mo_set,&
      65              :                                               get_mo_set,&
      66              :                                               init_mo_set,&
      67              :                                               mo_set_type
      68              :    USE qs_scf_methods,                  ONLY: eigensolver
      69              :    USE qs_scf_post_gpw,                 ONLY: make_lumo_gpw
      70              :    USE qs_scf_types,                    ONLY: ot_method_nr,&
      71              :                                               qs_scf_env_type
      72              :    USE qs_tddfpt2_types,                ONLY: tddfpt_ground_state_mos
      73              :    USE util,                            ONLY: sort
      74              :    USE xc_pot_saop,                     ONLY: add_saop_pot
      75              :    USE xtb_ks_matrix,                   ONLY: build_xtb_ks_matrix
      76              : #include "./base/base_uses.f90"
      77              : 
      78              :    IMPLICIT NONE
      79              : 
      80              :    PRIVATE
      81              : 
      82              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_tddfpt2_utils'
      83              : 
      84              :    LOGICAL, PARAMETER, PRIVATE          :: debug_this_module = .FALSE.
      85              :    ! number of first derivative components (3: d/dx, d/dy, d/dz)
      86              :    INTEGER, PARAMETER, PRIVATE          :: nderivs = 3
      87              :    INTEGER, PARAMETER, PRIVATE          :: maxspins = 2
      88              : 
      89              :    PUBLIC :: tddfpt_init_ground_state_mos, tddfpt_release_ground_state_mos
      90              :    PUBLIC :: tddfpt_guess_vectors, tddfpt_init_mos, tddfpt_oecorr
      91              :    PUBLIC :: tddfpt_total_number_of_states
      92              : 
      93              : ! **************************************************************************************************
      94              : 
      95              : CONTAINS
      96              : 
      97              : ! **************************************************************************************************
      98              : !> \brief Prepare MOs for TDDFPT Calculations
      99              : !> \param qs_env  Quickstep environment
     100              : !> \param gs_mos  ...
     101              : !> \param iounit ...
     102              : ! **************************************************************************************************
     103         1116 :    SUBROUTINE tddfpt_init_mos(qs_env, gs_mos, iounit)
     104              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     105              :       TYPE(tddfpt_ground_state_mos), DIMENSION(:), &
     106              :          POINTER                                         :: gs_mos
     107              :       INTEGER, INTENT(IN)                                :: iounit
     108              : 
     109              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'tddfpt_init_mos'
     110              : 
     111              :       INTEGER                                            :: handle, ispin, nmo_avail, nmo_occ, &
     112              :                                                             nmo_virt, nspins
     113              :       INTEGER, DIMENSION(2, 2)                           :: moc, mvt
     114              :       LOGICAL                                            :: print_virtuals_newtonx
     115         1116 :       REAL(kind=dp), DIMENSION(:), POINTER               :: evals_virt_spin
     116              :       TYPE(cell_type), POINTER                           :: cell
     117         1116 :       TYPE(cp_1d_r_p_type), DIMENSION(:), POINTER        :: evals_virt
     118              :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env
     119              :       TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:), &
     120         1116 :          TARGET                                          :: mos_virt
     121              :       TYPE(cp_fm_type), POINTER                          :: mos_virt_spin
     122         1116 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_ks, matrix_s
     123              :       TYPE(dft_control_type), POINTER                    :: dft_control
     124              :       TYPE(excited_energy_type), POINTER                 :: ex_env
     125         1116 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
     126              :       TYPE(qs_ks_env_type), POINTER                      :: ks_env
     127              :       TYPE(qs_scf_env_type), POINTER                     :: scf_env
     128              :       TYPE(section_vals_type), POINTER                   :: print_section
     129              :       TYPE(tddfpt2_control_type), POINTER                :: tddfpt_control
     130              : 
     131         1116 :       CALL timeset(routineN, handle)
     132              : 
     133              :       CALL get_qs_env(qs_env, blacs_env=blacs_env, cell=cell, dft_control=dft_control, &
     134         1116 :                       matrix_ks=matrix_ks, matrix_s=matrix_s, mos=mos, scf_env=scf_env)
     135         1116 :       tddfpt_control => dft_control%tddfpt2_control
     136         1116 :       IF (tddfpt_control%do_bse) THEN
     137            0 :          NULLIFY (ks_env, ex_env)
     138            0 :          CALL get_qs_env(qs_env, exstate_env=ex_env, ks_env=ks_env)
     139            0 :          CALL dbcsr_copy(matrix_ks(1)%matrix, ex_env%matrix_ks(1)%matrix)
     140            0 :          CALL set_ks_env(ks_env, matrix_ks=matrix_ks)
     141              :       END IF
     142              : 
     143         1116 :       CPASSERT(.NOT. ASSOCIATED(gs_mos))
     144              :       ! obtain occupied and virtual (unoccupied) ground-state Kohn-Sham orbitals
     145         1116 :       nspins = dft_control%nspins
     146         4616 :       ALLOCATE (gs_mos(nspins))
     147              : 
     148              :       ! check if virtuals should be constructed for NAMD interface with NEWTONX
     149         1116 :       print_section => section_vals_get_subs_vals(qs_env%input, "PROPERTIES%TDDFPT%PRINT")
     150         1116 :       CALL section_vals_val_get(print_section, "NAMD_PRINT%PRINT_VIRTUALS", l_val=print_virtuals_newtonx)
     151              : 
     152              :       ! when the number of unoccupied orbitals is limited and OT has been used
     153              :       ! for the ground-state DFT calculation,
     154              :       ! compute the missing unoccupied orbitals using OT as well.
     155         1116 :       NULLIFY (evals_virt, evals_virt_spin, mos_virt_spin)
     156         1116 :       IF (ASSOCIATED(scf_env)) THEN
     157         1116 :          IF ((scf_env%method == ot_method_nr .AND. tddfpt_control%nlumo > 0) .OR. &
     158              :              (scf_env%method == ot_method_nr .AND. print_virtuals_newtonx)) THEN
     159              :             ! As OT with ADDED_MOS/=0 is currently not implemented, the following block is equivalent to:
     160              :             ! nmo_virt = tddfpt_control%nlumo
     161              :             ! number of already computed unoccupied orbitals (added_mos) .
     162            2 :             nmo_virt = HUGE(0)
     163            4 :             DO ispin = 1, nspins
     164            2 :                CALL get_mo_set(mos(ispin), nmo=nmo_avail, homo=nmo_occ)
     165            4 :                nmo_virt = MIN(nmo_virt, nmo_avail - nmo_occ)
     166              :             END DO
     167              :             ! number of unoccupied orbitals to compute
     168            2 :             nmo_virt = tddfpt_control%nlumo - nmo_virt
     169            2 :             IF (.NOT. print_virtuals_newtonx) THEN
     170            0 :                IF (nmo_virt > 0) THEN
     171            0 :                   ALLOCATE (evals_virt(nspins), mos_virt(nspins))
     172              :                   ! the number of actually computed unoccupied orbitals will be stored as 'nmo_avail'
     173            0 :                   CALL make_lumo_gpw(qs_env, scf_env, mos_virt, evals_virt, nmo_virt, nmo_avail)
     174              :                END IF
     175              :             END IF
     176              :          END IF
     177              :       END IF
     178              : 
     179         2384 :       DO ispin = 1, nspins
     180         1268 :          IF (ASSOCIATED(evals_virt)) THEN
     181            0 :             evals_virt_spin => evals_virt(ispin)%array
     182              :          ELSE
     183         1268 :             NULLIFY (evals_virt_spin)
     184              :          END IF
     185         1268 :          IF (ALLOCATED(mos_virt)) THEN
     186            0 :             mos_virt_spin => mos_virt(ispin)
     187              :          ELSE
     188         1268 :             NULLIFY (mos_virt_spin)
     189              :          END IF
     190              :          CALL tddfpt_init_ground_state_mos(gs_mos=gs_mos(ispin), mo_set=mos(ispin), &
     191              :                                            nlumo=tddfpt_control%nlumo, &
     192              :                                            blacs_env=blacs_env, cholesky_method=cholesky_restore, &
     193              :                                            matrix_ks=matrix_ks(ispin)%matrix, matrix_s=matrix_s(1)%matrix, &
     194              :                                            mos_virt=mos_virt_spin, evals_virt=evals_virt_spin, &
     195         2384 :                                            qs_env=qs_env)
     196              :       END DO
     197              : 
     198         1116 :       moc = 0
     199         1116 :       mvt = 0
     200         2384 :       DO ispin = 1, nspins
     201         1268 :          CALL cp_fm_get_info(gs_mos(ispin)%mos_occ, nrow_global=moc(1, ispin), ncol_global=moc(2, ispin))
     202         2384 :          CALL cp_fm_get_info(gs_mos(ispin)%mos_virt, nrow_global=mvt(1, ispin), ncol_global=mvt(2, ispin))
     203              :       END DO
     204         1116 :       IF (iounit > 0) THEN
     205          558 :          WRITE (iounit, "(T2,A,T36,A)") "TDDFPT| Molecular Orbitals:", &
     206         1116 :             " Spin       AOs       Occ      Virt     Total"
     207         1192 :          DO ispin = 1, nspins
     208          634 :             WRITE (iounit, "(T2,A,T37,I4,4I10)") "TDDFPT| ", ispin, moc(1, ispin), moc(2, ispin), &
     209         1826 :                mvt(2, ispin), moc(2, ispin) + mvt(2, ispin)
     210              :          END DO
     211              :       END IF
     212              : 
     213         1116 :       IF (ASSOCIATED(evals_virt)) THEN
     214            0 :          DO ispin = 1, SIZE(evals_virt)
     215            0 :             IF (ASSOCIATED(evals_virt(ispin)%array)) DEALLOCATE (evals_virt(ispin)%array)
     216              :          END DO
     217            0 :          DEALLOCATE (evals_virt)
     218              :       END IF
     219              : 
     220         1116 :       CALL cp_fm_release(mos_virt)
     221              : 
     222         1116 :       CALL timestop(handle)
     223              : 
     224         3348 :    END SUBROUTINE tddfpt_init_mos
     225              : 
     226              : ! **************************************************************************************************
     227              : !> \brief Generate all virtual molecular orbitals for a given spin by diagonalising
     228              : !>        the corresponding Kohn-Sham matrix.
     229              : !> \param gs_mos           structure to store occupied and virtual molecular orbitals
     230              : !>                         (allocated and initialised on exit)
     231              : !> \param mo_set           ground state molecular orbitals for a given spin
     232              : !> \param nlumo            number of unoccupied states to consider (-1 means all states)
     233              : !> \param blacs_env        BLACS parallel environment
     234              : !> \param cholesky_method  Cholesky method to compute the inverse overlap matrix
     235              : !> \param matrix_ks        Kohn-Sham matrix for a given spin
     236              : !> \param matrix_s         overlap matrix
     237              : !> \param mos_virt         precomputed (OT) expansion coefficients of virtual molecular orbitals
     238              : !>                         (in addition to the ADDED_MOS, if present). NULL when no OT is in use.
     239              : !> \param evals_virt       orbital energies of precomputed (OT) virtual molecular orbitals.
     240              : !>                         NULL when no OT is in use.
     241              : !> \param qs_env ...
     242              : !> \par History
     243              : !>    * 05.2016 created as tddfpt_lumos() [Sergey Chulkov]
     244              : !>    * 06.2016 renamed, altered prototype [Sergey Chulkov]
     245              : !>    * 04.2019 limit the number of unoccupied states, orbital energy correction [Sergey Chulkov]
     246              : ! **************************************************************************************************
     247         1268 :    SUBROUTINE tddfpt_init_ground_state_mos(gs_mos, mo_set, nlumo, blacs_env, cholesky_method, matrix_ks, matrix_s, &
     248              :                                            mos_virt, evals_virt, qs_env)
     249              :       TYPE(tddfpt_ground_state_mos)                      :: gs_mos
     250              :       TYPE(mo_set_type), INTENT(IN)                      :: mo_set
     251              :       INTEGER, INTENT(in)                                :: nlumo
     252              :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env
     253              :       INTEGER, INTENT(in)                                :: cholesky_method
     254              :       TYPE(dbcsr_type), POINTER                          :: matrix_ks, matrix_s
     255              :       TYPE(cp_fm_type), INTENT(IN), POINTER              :: mos_virt
     256              :       REAL(kind=dp), DIMENSION(:), POINTER               :: evals_virt
     257              :       TYPE(qs_environment_type), INTENT(in), POINTER     :: qs_env
     258              : 
     259              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'tddfpt_init_ground_state_mos'
     260              :       REAL(kind=dp), PARAMETER                           :: eps_dp = EPSILON(0.0_dp)
     261              : 
     262              :       INTEGER :: cholesky_method_inout, handle, icol_global, icol_local, imo, iounit, irow_global, &
     263              :          irow_local, nao, ncol_local, nelectrons, nmo_occ, nmo_scf, nmo_virt, nrow_local, sign_int
     264         1268 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: minrow_neg_array, minrow_pos_array, &
     265         1268 :                                                             sum_sign_array
     266         1268 :       INTEGER, DIMENSION(:), POINTER                     :: col_indices, row_indices
     267              :       LOGICAL                                            :: do_eigen, print_phases
     268              :       REAL(kind=dp)                                      :: element, maxocc
     269              :       REAL(KIND=dp), CONTIGUOUS, DIMENSION(:, :), &
     270         1268 :          POINTER                                         :: my_block
     271         1268 :       REAL(kind=dp), DIMENSION(:), POINTER               :: mo_evals_extended, mo_occ_extended, &
     272         1268 :                                                             mo_occ_scf
     273              :       TYPE(cp_fm_struct_type), POINTER                   :: ao_ao_fm_struct, ao_mo_occ_fm_struct, &
     274              :                                                             ao_mo_virt_fm_struct, wfn_fm_struct
     275              :       TYPE(cp_fm_type)                                   :: matrix_ks_fm, ortho_fm, work_fm, &
     276              :                                                             work_fm_virt
     277              :       TYPE(cp_fm_type), POINTER                          :: mo_coeff_extended
     278              :       TYPE(cp_logger_type), POINTER                      :: logger
     279              :       TYPE(mo_set_type), POINTER                         :: mos_extended
     280              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     281              :       TYPE(section_vals_type), POINTER                   :: print_section
     282              : 
     283         1268 :       CALL timeset(routineN, handle)
     284              : 
     285         1268 :       NULLIFY (logger)
     286         1268 :       logger => cp_get_default_logger()
     287         1268 :       iounit = cp_logger_get_default_io_unit(logger)
     288              : 
     289         1268 :       CALL blacs_env%get(para_env=para_env)
     290              : 
     291              :       CALL get_mo_set(mo_set, nao=nao, nmo=nmo_scf, homo=nmo_occ, maxocc=maxocc, &
     292         1268 :                       nelectron=nelectrons, occupation_numbers=mo_occ_scf)
     293              : 
     294         1268 :       print_section => section_vals_get_subs_vals(qs_env%input, "PROPERTIES%TDDFPT%PRINT")
     295         1268 :       CALL section_vals_val_get(print_section, "NAMD_PRINT%PRINT_PHASES", l_val=print_phases)
     296              : 
     297         1268 :       nmo_virt = nao - nmo_occ
     298         1268 :       IF (nlumo >= 0) &
     299            0 :          nmo_virt = MIN(nmo_virt, nlumo)
     300              : 
     301         1268 :       IF (nmo_virt <= 0) &
     302              :          CALL cp_abort(__LOCATION__, &
     303            0 :                        'At least one unoccupied molecular orbital is required to calculate excited states.')
     304              : 
     305         1268 :       do_eigen = .FALSE.
     306              :       ! diagonalise the Kohn-Sham matrix one more time if the number of available unoccupied states are too small
     307         1268 :       IF (ASSOCIATED(evals_virt)) THEN
     308            0 :          CPASSERT(ASSOCIATED(mos_virt))
     309            0 :          IF (nmo_virt > nmo_scf - nmo_occ + SIZE(evals_virt)) do_eigen = .TRUE.
     310              :       ELSE
     311         1268 :          IF (nmo_virt > nmo_scf - nmo_occ) do_eigen = .TRUE.
     312              :       END IF
     313              : 
     314              :       ! ++ allocate storage space for gs_mos
     315         1268 :       NULLIFY (ao_mo_occ_fm_struct, ao_mo_virt_fm_struct)
     316              :       ! Tiny fix (A.Sinyavskiy)
     317              :       CALL cp_fm_struct_create(ao_mo_occ_fm_struct, template_fmstruct=mo_set%mo_coeff%matrix_struct, &
     318         1268 :                                ncol_global=nmo_occ, context=blacs_env)
     319              :       CALL cp_fm_struct_create(ao_mo_virt_fm_struct, template_fmstruct=mo_set%mo_coeff%matrix_struct, &
     320         1268 :                                ncol_global=nmo_virt, context=blacs_env)
     321              : 
     322         1268 :       NULLIFY (gs_mos%mos_occ, gs_mos%mos_virt, gs_mos%evals_occ_matrix)
     323         1268 :       ALLOCATE (gs_mos%mos_occ, gs_mos%mos_virt)
     324         1268 :       CALL cp_fm_create(gs_mos%mos_occ, ao_mo_occ_fm_struct)
     325         1268 :       CALL cp_fm_create(gs_mos%mos_virt, ao_mo_virt_fm_struct)
     326         1268 :       gs_mos%nmo_occ = nmo_occ
     327              : 
     328         3804 :       ALLOCATE (gs_mos%evals_occ(nmo_occ))
     329         3804 :       ALLOCATE (gs_mos%evals_virt(nmo_virt))
     330         2536 :       ALLOCATE (gs_mos%phases_occ(nmo_occ))
     331         2536 :       ALLOCATE (gs_mos%phases_virt(nmo_virt))
     332              : 
     333              :       ! ++ nullify pointers
     334         1268 :       NULLIFY (ao_ao_fm_struct, wfn_fm_struct)
     335         1268 :       NULLIFY (mos_extended, mo_coeff_extended, mo_evals_extended, mo_occ_extended)
     336              : 
     337         1268 :       IF (do_eigen) THEN
     338              :          ! ++ set of molecular orbitals
     339         1260 :          CALL cp_fm_struct_create(ao_ao_fm_struct, nrow_global=nao, ncol_global=nao, context=blacs_env)
     340         1260 :          CALL cp_fm_struct_create(wfn_fm_struct, nrow_global=nao, ncol_global=nmo_occ + nmo_virt, context=blacs_env)
     341         1260 :          ALLOCATE (mos_extended)
     342              :          CALL allocate_mo_set(mos_extended, nao, nmo_occ + nmo_virt, nelectrons, &
     343         1260 :                               REAL(nelectrons, dp), maxocc, flexible_electron_count=0.0_dp)
     344         1260 :          CALL init_mo_set(mos_extended, fm_struct=wfn_fm_struct, name="mos-extended")
     345         1260 :          CALL cp_fm_struct_release(wfn_fm_struct)
     346              :          CALL get_mo_set(mos_extended, mo_coeff=mo_coeff_extended, &
     347         1260 :                          eigenvalues=mo_evals_extended, occupation_numbers=mo_occ_extended)
     348              : 
     349              :          ! use the explicit loop in order to avoid temporary arrays.
     350              :          !
     351              :          ! The assignment statement : mo_occ_extended(1:nmo_scf) = mo_occ_scf(1:nmo_scf)
     352              :          ! implies temporary arrays as a compiler does not know in advance that the pointers
     353              :          ! on both sides of the statement point to non-overlapped memory regions
     354         7908 :          DO imo = 1, nmo_scf
     355         7908 :             mo_occ_extended(imo) = mo_occ_scf(imo)
     356              :          END DO
     357        21880 :          mo_occ_extended(nmo_scf + 1:) = 0.0_dp
     358              : 
     359              :          ! ++ allocate temporary matrices
     360         1260 :          CALL cp_fm_create(matrix_ks_fm, ao_ao_fm_struct)
     361         1260 :          CALL cp_fm_create(ortho_fm, ao_ao_fm_struct)
     362         1260 :          CALL cp_fm_create(work_fm, ao_ao_fm_struct)
     363         1260 :          CALL cp_fm_struct_release(ao_ao_fm_struct)
     364              : 
     365              :          ! some stuff from the subroutine general_eigenproblem()
     366         1260 :          CALL copy_dbcsr_to_fm(matrix_s, ortho_fm)
     367         1260 :          CALL copy_dbcsr_to_fm(matrix_ks, matrix_ks_fm)
     368              : 
     369         1260 :          IF (cholesky_method == cholesky_dbcsr) THEN
     370            0 :             CPABORT('CHOLESKY DBCSR_INVERSE is not implemented in TDDFT.')
     371         1260 :          ELSE IF (cholesky_method == cholesky_off) THEN
     372            0 :             CPABORT('CHOLESKY OFF is not implemented in TDDFT.')
     373              :          ELSE
     374         1260 :             CALL cp_fm_cholesky_decompose(ortho_fm)
     375         1260 :             IF (cholesky_method == cholesky_inverse) THEN
     376            0 :                CALL cp_fm_triangular_invert(ortho_fm)
     377              :             END IF
     378              : 
     379              :             ! need to store 'cholesky_method' in a temporary variable, as the subroutine eigensolver()
     380              :             ! will update this variable
     381         1260 :             cholesky_method_inout = cholesky_method
     382              :             CALL eigensolver(matrix_ks_fm=matrix_ks_fm, mo_set=mos_extended, ortho=ortho_fm, &
     383              :                              work=work_fm, cholesky_method=cholesky_method_inout, &
     384         1260 :                              do_level_shift=.FALSE., level_shift=0.0_dp, use_jacobi=.FALSE.)
     385              :          END IF
     386              : 
     387              :          ! -- clean up needless matrices
     388         1260 :          CALL cp_fm_release(work_fm)
     389         1260 :          CALL cp_fm_release(ortho_fm)
     390         1260 :          CALL cp_fm_release(matrix_ks_fm)
     391              :       ELSE
     392              :          CALL get_mo_set(mo_set, mo_coeff=mo_coeff_extended, &
     393            8 :                          eigenvalues=mo_evals_extended, occupation_numbers=mo_occ_extended)
     394              :       END IF
     395              : 
     396              :       ! compute the phase of molecular orbitals;
     397              :       ! matrix work_fm holds occupied molecular orbital coefficients distributed among all the processors
     398              :       !CALL cp_fm_struct_create(ao_mo_occ_fm_struct, nrow_global=nao, ncol_global=nmo_occ, context=blacs_env)
     399         1268 :       CALL cp_fm_create(work_fm, ao_mo_occ_fm_struct)
     400         1268 :       CALL cp_fm_struct_release(ao_mo_occ_fm_struct)
     401              : 
     402         1268 :       CALL cp_fm_to_fm(mo_coeff_extended, work_fm, ncol=nmo_occ, source_start=1, target_start=1)
     403              :       CALL cp_fm_get_info(work_fm, nrow_local=nrow_local, ncol_local=ncol_local, &
     404         1268 :                           row_indices=row_indices, col_indices=col_indices, local_data=my_block)
     405              : 
     406         6340 :       ALLOCATE (minrow_neg_array(nmo_occ), minrow_pos_array(nmo_occ), sum_sign_array(nmo_occ))
     407         7928 :       minrow_neg_array(:) = nao
     408         7928 :       minrow_pos_array(:) = nao
     409         7928 :       sum_sign_array(:) = 0
     410         7928 :       DO icol_local = 1, ncol_local
     411         6660 :          icol_global = col_indices(icol_local)
     412              : 
     413       227393 :          DO irow_local = 1, nrow_local
     414       219465 :             element = my_block(irow_local, icol_local)
     415              : 
     416       219465 :             sign_int = 0
     417       219465 :             IF (element >= eps_dp) THEN
     418              :                sign_int = 1
     419       110911 :             ELSE IF (element <= -eps_dp) THEN
     420       110379 :                sign_int = -1
     421              :             END IF
     422              : 
     423       219465 :             sum_sign_array(icol_global) = sum_sign_array(icol_global) + sign_int
     424              : 
     425       219465 :             irow_global = row_indices(irow_local)
     426       226125 :             IF (sign_int > 0) THEN
     427       108554 :                IF (minrow_pos_array(icol_global) > irow_global) &
     428         6542 :                   minrow_pos_array(icol_global) = irow_global
     429       110911 :             ELSE IF (sign_int < 0) THEN
     430       110379 :                IF (minrow_neg_array(icol_global) > irow_global) &
     431         6412 :                   minrow_neg_array(icol_global) = irow_global
     432              :             END IF
     433              :          END DO
     434              :       END DO
     435              : 
     436         1268 :       CALL para_env%sum(sum_sign_array)
     437         1268 :       CALL para_env%min(minrow_neg_array)
     438         1268 :       CALL para_env%min(minrow_pos_array)
     439              : 
     440         7928 :       DO icol_local = 1, nmo_occ
     441         7928 :          IF (sum_sign_array(icol_local) > 0) THEN
     442              :             ! most of the expansion coefficients are positive => MO's phase = +1
     443         2962 :             gs_mos%phases_occ(icol_local) = 1.0_dp
     444         3698 :          ELSE IF (sum_sign_array(icol_local) < 0) THEN
     445              :             ! most of the expansion coefficients are negative => MO's phase = -1
     446         3440 :             gs_mos%phases_occ(icol_local) = -1.0_dp
     447              :          ELSE
     448              :             ! equal number of positive and negative expansion coefficients
     449          258 :             IF (minrow_pos_array(icol_local) <= minrow_neg_array(icol_local)) THEN
     450              :                ! the first positive expansion coefficient has a lower index then
     451              :                ! the first negative expansion coefficient; MO's phase = +1
     452          138 :                gs_mos%phases_occ(icol_local) = 1.0_dp
     453              :             ELSE
     454              :                ! MO's phase = -1
     455          120 :                gs_mos%phases_occ(icol_local) = -1.0_dp
     456              :             END IF
     457              :          END IF
     458              :       END DO
     459              : 
     460         1268 :       DEALLOCATE (minrow_neg_array, minrow_pos_array, sum_sign_array)
     461              : 
     462              :       ! return the requested occupied and virtual molecular orbitals and corresponding orbital energies
     463         1268 :       CALL cp_fm_to_fm(mo_coeff_extended, gs_mos%mos_occ, ncol=nmo_occ, source_start=1, target_start=1)
     464         7928 :       gs_mos%evals_occ(1:nmo_occ) = mo_evals_extended(1:nmo_occ)
     465              : 
     466         1268 :       IF (ASSOCIATED(evals_virt) .AND. (.NOT. do_eigen) .AND. nmo_virt > nmo_scf - nmo_occ) THEN
     467              :          CALL cp_fm_to_fm(mo_coeff_extended, gs_mos%mos_virt, ncol=nmo_scf - nmo_occ, &
     468            0 :                           source_start=nmo_occ + 1, target_start=1)
     469              :          CALL cp_fm_to_fm(mos_virt, gs_mos%mos_virt, ncol=nmo_virt - (nmo_scf - nmo_occ), &
     470            0 :                           source_start=1, target_start=nmo_scf - nmo_occ + 1)
     471            0 :          gs_mos%evals_virt(1:nmo_scf - nmo_occ) = evals_virt(nmo_occ + 1:nmo_occ + nmo_scf)
     472            0 :          gs_mos%evals_virt(nmo_scf - nmo_occ + 1:nmo_virt) = evals_virt(1:nmo_virt - (nmo_scf - nmo_occ))
     473              :       ELSE
     474         1268 :          CALL cp_fm_to_fm(mo_coeff_extended, gs_mos%mos_virt, ncol=nmo_virt, source_start=nmo_occ + 1, target_start=1)
     475        22048 :          gs_mos%evals_virt(1:nmo_virt) = mo_evals_extended(nmo_occ + 1:nmo_occ + nmo_virt)
     476              :       END IF
     477              : 
     478         1268 :       IF (print_phases) THEN
     479              :          ! compute the phase of molecular orbitals;
     480              :          ! matrix work_fm holds virtual molecular orbital coefficients distributed among all the processors
     481              :          !CALL cp_fm_struct_create(ao_mo_occ_fm_struct, nrow_global=nao, ncol_global=nmo_occ, context=blacs_env)
     482            0 :          CALL cp_fm_create(work_fm_virt, ao_mo_virt_fm_struct)
     483              : 
     484            0 :          CALL cp_fm_to_fm(gs_mos%mos_virt, work_fm_virt, ncol=nmo_virt, source_start=1, target_start=1)
     485              :          CALL cp_fm_get_info(work_fm_virt, nrow_local=nrow_local, ncol_local=ncol_local, &
     486            0 :                              row_indices=row_indices, col_indices=col_indices, local_data=my_block)
     487              : 
     488            0 :          ALLOCATE (minrow_neg_array(nmo_virt), minrow_pos_array(nmo_virt), sum_sign_array(nmo_virt))
     489            0 :          minrow_neg_array(:) = nao
     490            0 :          minrow_pos_array(:) = nao
     491            0 :          sum_sign_array(:) = 0
     492            0 :          DO icol_local = 1, ncol_local
     493            0 :             icol_global = col_indices(icol_local)
     494              : 
     495            0 :             DO irow_local = 1, nrow_local
     496            0 :                element = my_block(irow_local, icol_local)
     497              : 
     498            0 :                sign_int = 0
     499            0 :                IF (element >= eps_dp) THEN
     500              :                   sign_int = 1
     501            0 :                ELSE IF (element <= -eps_dp) THEN
     502            0 :                   sign_int = -1
     503              :                END IF
     504              : 
     505            0 :                sum_sign_array(icol_global) = sum_sign_array(icol_global) + sign_int
     506              : 
     507            0 :                irow_global = row_indices(irow_local)
     508            0 :                IF (sign_int > 0) THEN
     509            0 :                   IF (minrow_pos_array(icol_global) > irow_global) &
     510            0 :                      minrow_pos_array(icol_global) = irow_global
     511            0 :                ELSE IF (sign_int < 0) THEN
     512            0 :                   IF (minrow_neg_array(icol_global) > irow_global) &
     513            0 :                      minrow_neg_array(icol_global) = irow_global
     514              :                END IF
     515              :             END DO
     516              :          END DO
     517              : 
     518            0 :          CALL para_env%sum(sum_sign_array)
     519            0 :          CALL para_env%min(minrow_neg_array)
     520            0 :          CALL para_env%min(minrow_pos_array)
     521            0 :          DO icol_local = 1, nmo_virt
     522            0 :             IF (sum_sign_array(icol_local) > 0) THEN
     523              :                ! most of the expansion coefficients are positive => MO's phase = +1
     524            0 :                gs_mos%phases_virt(icol_local) = 1.0_dp
     525            0 :             ELSE IF (sum_sign_array(icol_local) < 0) THEN
     526              :                ! most of the expansion coefficients are negative => MO's phase = -1
     527            0 :                gs_mos%phases_virt(icol_local) = -1.0_dp
     528              :             ELSE
     529              :                ! equal number of positive and negative expansion coefficients
     530            0 :                IF (minrow_pos_array(icol_local) <= minrow_neg_array(icol_local)) THEN
     531              :                   ! the first positive expansion coefficient has a lower index then
     532              :                   ! the first negative expansion coefficient; MO's phase = +1
     533            0 :                   gs_mos%phases_virt(icol_local) = 1.0_dp
     534              :                ELSE
     535              :                   ! MO's phase = -1
     536            0 :                   gs_mos%phases_virt(icol_local) = -1.0_dp
     537              :                END IF
     538              :             END IF
     539              :          END DO
     540            0 :          DEALLOCATE (minrow_neg_array, minrow_pos_array, sum_sign_array)
     541            0 :          CALL cp_fm_release(work_fm_virt)
     542              :       END IF !print_phases
     543         1268 :       CALL cp_fm_struct_release(ao_mo_virt_fm_struct) ! here after print_phases
     544              : 
     545         1268 :       CALL cp_fm_release(work_fm)
     546              : 
     547         1268 :       IF (do_eigen) THEN
     548         1260 :          CALL deallocate_mo_set(mos_extended)
     549         1260 :          DEALLOCATE (mos_extended)
     550              :       END IF
     551              : 
     552         1268 :       CALL timestop(handle)
     553              : 
     554         7608 :    END SUBROUTINE tddfpt_init_ground_state_mos
     555              : 
     556              : ! **************************************************************************************************
     557              : !> \brief Release molecular orbitals.
     558              : !> \param gs_mos  structure that holds occupied and virtual molecular orbitals
     559              : !> \par History
     560              : !>    * 06.2016 created [Sergey Chulkov]
     561              : ! **************************************************************************************************
     562         1268 :    SUBROUTINE tddfpt_release_ground_state_mos(gs_mos)
     563              :       TYPE(tddfpt_ground_state_mos), INTENT(inout)       :: gs_mos
     564              : 
     565              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'tddfpt_release_ground_state_mos'
     566              : 
     567              :       INTEGER                                            :: handle
     568              : 
     569         1268 :       CALL timeset(routineN, handle)
     570              : 
     571         1268 :       IF (ALLOCATED(gs_mos%phases_occ)) &
     572         1268 :          DEALLOCATE (gs_mos%phases_occ)
     573              : 
     574         1268 :       IF (ALLOCATED(gs_mos%evals_virt)) &
     575         1268 :          DEALLOCATE (gs_mos%evals_virt)
     576              : 
     577         1268 :       IF (ALLOCATED(gs_mos%evals_occ)) &
     578         1268 :          DEALLOCATE (gs_mos%evals_occ)
     579              : 
     580         1268 :       IF (ALLOCATED(gs_mos%phases_virt)) &
     581         1268 :          DEALLOCATE (gs_mos%phases_virt)
     582              : 
     583         1268 :       IF (ALLOCATED(gs_mos%index_active)) &
     584         1268 :          DEALLOCATE (gs_mos%index_active)
     585              : 
     586         1268 :       IF (ASSOCIATED(gs_mos%evals_occ_matrix)) THEN
     587           36 :          CALL cp_fm_release(gs_mos%evals_occ_matrix)
     588           36 :          DEALLOCATE (gs_mos%evals_occ_matrix)
     589              :       END IF
     590              : 
     591         1268 :       IF (ASSOCIATED(gs_mos%mos_virt)) THEN
     592         1268 :          CALL cp_fm_release(gs_mos%mos_virt)
     593         1268 :          DEALLOCATE (gs_mos%mos_virt)
     594              :       END IF
     595              : 
     596         1268 :       IF (ASSOCIATED(gs_mos%mos_occ)) THEN
     597         1268 :          CALL cp_fm_release(gs_mos%mos_occ)
     598         1268 :          DEALLOCATE (gs_mos%mos_occ)
     599              :       END IF
     600              : 
     601         1268 :       IF (ASSOCIATED(gs_mos%mos_active)) THEN
     602         1268 :          CALL cp_fm_release(gs_mos%mos_active)
     603         1268 :          DEALLOCATE (gs_mos%mos_active)
     604              :       END IF
     605              : 
     606         1268 :       CALL timestop(handle)
     607              : 
     608         1268 :    END SUBROUTINE tddfpt_release_ground_state_mos
     609              : 
     610              : ! **************************************************************************************************
     611              : !> \brief Callculate orbital corrected KS matrix for TDDFPT
     612              : !> \param qs_env  Quickstep environment
     613              : !> \param gs_mos ...
     614              : !> \param matrix_ks_oep ...
     615              : ! **************************************************************************************************
     616         1116 :    SUBROUTINE tddfpt_oecorr(qs_env, gs_mos, matrix_ks_oep)
     617              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     618              :       TYPE(tddfpt_ground_state_mos), DIMENSION(:), &
     619              :          POINTER                                         :: gs_mos
     620              :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_ks_oep
     621              : 
     622              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'tddfpt_oecorr'
     623              : 
     624              :       INTEGER                                            :: handle, iounit, ispin, nao, nmo_occ, &
     625              :                                                             nspins
     626              :       LOGICAL                                            :: do_hfx
     627              :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env
     628              :       TYPE(cp_fm_struct_type), POINTER                   :: ao_mo_occ_fm_struct, &
     629              :                                                             mo_occ_mo_occ_fm_struct
     630              :       TYPE(cp_fm_type)                                   :: work_fm
     631              :       TYPE(cp_logger_type), POINTER                      :: logger
     632         1116 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_ks
     633              :       TYPE(dft_control_type), POINTER                    :: dft_control
     634              :       TYPE(section_vals_type), POINTER                   :: hfx_section, xc_fun_empty, &
     635              :                                                             xc_fun_original
     636              :       TYPE(tddfpt2_control_type), POINTER                :: tddfpt_control
     637              : 
     638         1116 :       CALL timeset(routineN, handle)
     639              : 
     640         1116 :       NULLIFY (logger)
     641         1116 :       logger => cp_get_default_logger()
     642         1116 :       iounit = cp_logger_get_default_io_unit(logger)
     643              : 
     644         1116 :       CALL get_qs_env(qs_env, blacs_env=blacs_env, dft_control=dft_control, matrix_ks=matrix_ks)
     645         1116 :       tddfpt_control => dft_control%tddfpt2_control
     646              : 
     647              :       ! obtain corrected KS-matrix
     648              :       ! We should 'save' the energy values?
     649         1116 :       nspins = SIZE(gs_mos)
     650         1116 :       NULLIFY (matrix_ks_oep)
     651         1116 :       IF (tddfpt_control%oe_corr /= oe_none) THEN
     652           30 :          IF (iounit > 0) THEN
     653           15 :             WRITE (iounit, "(1X,A)") "", &
     654           15 :                "-------------------------------------------------------------------------------", &
     655           15 :                "-                    Orbital Eigenvalue Correction Started                    -", &
     656           30 :                "-------------------------------------------------------------------------------"
     657              :          END IF
     658              : 
     659              :          CALL cp_warn(__LOCATION__, &
     660              :                       "Orbital energy correction potential is an experimental feature. "// &
     661           30 :                       "Use it with extreme care")
     662              : 
     663           30 :          hfx_section => section_vals_get_subs_vals(qs_env%input, "DFT%XC%HF")
     664           30 :          CALL section_vals_get(hfx_section, explicit=do_hfx)
     665           30 :          IF (do_hfx) THEN
     666              :             CALL cp_abort(__LOCATION__, &
     667              :                           "Implementation of orbital energy correction XC-potentials is "// &
     668            0 :                           "currently incompatible with exact-exchange functionals")
     669              :          END IF
     670              : 
     671           30 :          CALL dbcsr_allocate_matrix_set(matrix_ks_oep, nspins)
     672           66 :          DO ispin = 1, nspins
     673           36 :             CALL dbcsr_init_p(matrix_ks_oep(ispin)%matrix)
     674           66 :             CALL dbcsr_copy(matrix_ks_oep(ispin)%matrix, matrix_ks(ispin)%matrix)
     675              :          END DO
     676              : 
     677              :          ! KS-matrix without XC-terms
     678           30 :          xc_fun_original => section_vals_get_subs_vals(qs_env%input, "DFT%XC%XC_FUNCTIONAL")
     679           30 :          CALL section_vals_retain(xc_fun_original)
     680           30 :          NULLIFY (xc_fun_empty)
     681           30 :          CALL section_vals_create(xc_fun_empty, xc_fun_original%section)
     682           30 :          CALL section_vals_set_subs_vals(qs_env%input, "DFT%XC%XC_FUNCTIONAL", xc_fun_empty)
     683           30 :          CALL section_vals_release(xc_fun_empty)
     684              : 
     685           30 :          IF (dft_control%qs_control%semi_empirical) THEN
     686            0 :             CPABORT("TDDFPT with SE not possible")
     687           30 :          ELSEIF (dft_control%qs_control%dftb) THEN
     688            0 :             CPABORT("TDDFPT with DFTB not possible")
     689           30 :          ELSEIF (dft_control%qs_control%xtb) THEN
     690              :             CALL build_xtb_ks_matrix(qs_env, calculate_forces=.FALSE., just_energy=.FALSE., &
     691           16 :                                      ext_ks_matrix=matrix_ks_oep)
     692              :          ELSE
     693              :             CALL qs_ks_build_kohn_sham_matrix(qs_env, calculate_forces=.FALSE., just_energy=.FALSE., &
     694           14 :                                               ext_ks_matrix=matrix_ks_oep)
     695              :          END IF
     696              : 
     697              :          IF (tddfpt_control%oe_corr == oe_saop .OR. &
     698           30 :              tddfpt_control%oe_corr == oe_lb .OR. &
     699              :              tddfpt_control%oe_corr == oe_gllb) THEN
     700           14 :             IF (iounit > 0) THEN
     701            7 :                WRITE (iounit, "(T2,A)") " Orbital energy correction of SAOP type "
     702              :             END IF
     703           14 :             CALL add_saop_pot(matrix_ks_oep, qs_env, tddfpt_control%oe_corr)
     704           16 :          ELSE IF (tddfpt_control%oe_corr == oe_shift) THEN
     705           16 :             IF (iounit > 0) THEN
     706              :                WRITE (iounit, "(T2,A,T71,F10.3)") &
     707            8 :                   " Virtual Orbital Eigenvalue Shift [eV] ", tddfpt_control%ev_shift*evolt
     708              :                WRITE (iounit, "(T2,A,T71,F10.3)") &
     709            8 :                   " Open Shell Orbital Eigenvalue Shift [eV] ", tddfpt_control%eos_shift*evolt
     710              :             END IF
     711              :             CALL ev_shift_operator(qs_env, gs_mos, matrix_ks_oep, &
     712           16 :                                    tddfpt_control%ev_shift, tddfpt_control%eos_shift)
     713              :          ELSE
     714              :             CALL cp_abort(__LOCATION__, &
     715            0 :                           "Unimplemented orbital energy correction potential")
     716              :          END IF
     717           30 :          CALL section_vals_set_subs_vals(qs_env%input, "DFT%XC%XC_FUNCTIONAL", xc_fun_original)
     718           30 :          CALL section_vals_release(xc_fun_original)
     719              : 
     720              :          ! compute 'evals_occ_matrix'
     721           30 :          CALL dbcsr_get_info(matrix_ks(1)%matrix, nfullrows_total=nao)
     722           30 :          NULLIFY (mo_occ_mo_occ_fm_struct)
     723           66 :          DO ispin = 1, nspins
     724           36 :             nmo_occ = SIZE(gs_mos(ispin)%evals_occ)
     725              :             CALL cp_fm_struct_create(mo_occ_mo_occ_fm_struct, nrow_global=nmo_occ, ncol_global=nmo_occ, &
     726           36 :                                      context=blacs_env)
     727           36 :             ALLOCATE (gs_mos(ispin)%evals_occ_matrix)
     728           36 :             CALL cp_fm_create(gs_mos(ispin)%evals_occ_matrix, mo_occ_mo_occ_fm_struct)
     729           36 :             CALL cp_fm_struct_release(mo_occ_mo_occ_fm_struct)
     730              :             ! work_fm is a temporary [nao x nmo_occ] matrix
     731              :             CALL cp_fm_struct_create(ao_mo_occ_fm_struct, nrow_global=nao, ncol_global=nmo_occ, &
     732           36 :                                      context=blacs_env)
     733           36 :             CALL cp_fm_create(work_fm, ao_mo_occ_fm_struct)
     734           36 :             CALL cp_fm_struct_release(ao_mo_occ_fm_struct)
     735              :             CALL cp_dbcsr_sm_fm_multiply(matrix_ks_oep(ispin)%matrix, gs_mos(ispin)%mos_occ, &
     736           36 :                                          work_fm, ncol=nmo_occ, alpha=1.0_dp, beta=0.0_dp)
     737              :             CALL parallel_gemm('T', 'N', nmo_occ, nmo_occ, nao, 1.0_dp, gs_mos(ispin)%mos_occ, work_fm, &
     738           36 :                                0.0_dp, gs_mos(ispin)%evals_occ_matrix)
     739          102 :             CALL cp_fm_release(work_fm)
     740              :          END DO
     741           30 :          IF (iounit > 0) THEN
     742              :             WRITE (iounit, "(1X,A)") &
     743           15 :                "-------------------------------------------------------------------------------"
     744              :          END IF
     745              : 
     746              :       END IF
     747              : 
     748         1116 :       CALL timestop(handle)
     749              : 
     750         1116 :    END SUBROUTINE tddfpt_oecorr
     751              : 
     752              : ! **************************************************************************************************
     753              : !> \brief Compute the number of possible singly excited states (occ -> virt)
     754              : !> \param tddfpt_control ...
     755              : !> \param gs_mos          occupied and virtual molecular orbitals optimised for the ground state
     756              : !> \return the number of possible single excitations
     757              : !> \par History
     758              : !>    * 01.2017 created [Sergey Chulkov]
     759              : ! **************************************************************************************************
     760         1772 :    PURE FUNCTION tddfpt_total_number_of_states(tddfpt_control, gs_mos) RESULT(nstates_total)
     761              :       TYPE(tddfpt2_control_type), POINTER                :: tddfpt_control
     762              :       TYPE(tddfpt_ground_state_mos), DIMENSION(:), &
     763              :          INTENT(in)                                      :: gs_mos
     764              :       INTEGER(kind=int_8)                                :: nstates_total
     765              : 
     766              :       INTEGER                                            :: ispin, nspins
     767              : 
     768         1772 :       nstates_total = 0
     769         1772 :       nspins = SIZE(gs_mos)
     770              : 
     771         1772 :       IF (tddfpt_control%spinflip == no_sf_tddfpt) THEN
     772              :          ! Total number of possible excitations for spin-conserving TDDFT
     773         3665 :          DO ispin = 1, nspins
     774              :             nstates_total = nstates_total + &
     775              :                             gs_mos(ispin)%nmo_active* &
     776         3665 :                             SIZE(gs_mos(ispin)%evals_virt, kind=int_8)
     777              :          END DO
     778              :       ELSE
     779              :          ! Total number of possible excitations for spin-flip TDDFT
     780              :          nstates_total = gs_mos(1)%nmo_active* &
     781           37 :                          SIZE(gs_mos(2)%evals_virt, kind=int_8)
     782              :       END IF
     783         1772 :    END FUNCTION tddfpt_total_number_of_states
     784              : 
     785              : ! **************************************************************************************************
     786              : !> \brief Create a shift operator on virtual/open shell space
     787              : !>        Shift operator = Edelta*Q  Q: projector on virtual space (1-PS)
     788              : !>                                      projector on open shell space PosS
     789              : !> \param qs_env the qs_env that is perturbed by this p_env
     790              : !> \param gs_mos  ...
     791              : !> \param matrix_ks ...
     792              : !> \param ev_shift ...
     793              : !> \param eos_shift ...
     794              : !> \par History
     795              : !>      02.04.2019 adapted for TDDFT use from p_env (JGH)
     796              : !> \author JGH
     797              : ! **************************************************************************************************
     798           16 :    SUBROUTINE ev_shift_operator(qs_env, gs_mos, matrix_ks, ev_shift, eos_shift)
     799              : 
     800              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     801              :       TYPE(tddfpt_ground_state_mos), DIMENSION(:), &
     802              :          POINTER                                         :: gs_mos
     803              :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_ks
     804              :       REAL(KIND=dp), INTENT(IN)                          :: ev_shift, eos_shift
     805              : 
     806              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'ev_shift_operator'
     807              : 
     808              :       INTEGER                                            :: handle, ispin, n_spins, na, nb, nhomo, &
     809              :                                                             nl, nos, nrow, nu, nvirt
     810              :       TYPE(cp_fm_struct_type), POINTER                   :: fmstruct
     811              :       TYPE(cp_fm_type)                                   :: cmos, cvec
     812              :       TYPE(cp_fm_type), POINTER                          :: coeff
     813           16 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_s
     814              :       TYPE(dbcsr_type), POINTER                          :: smat
     815           16 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
     816              : 
     817           16 :       CALL timeset(routineN, handle)
     818              : 
     819           16 :       n_spins = SIZE(gs_mos)
     820           16 :       CPASSERT(n_spins == SIZE(matrix_ks))
     821              : 
     822           16 :       IF (eos_shift /= 0.0_dp .AND. n_spins > 1) THEN
     823            0 :          CPABORT("eos_shift not implemented")
     824            0 :          CALL get_qs_env(qs_env, mos=mos, matrix_s=matrix_s)
     825            0 :          smat => matrix_s(1)%matrix
     826            0 :          CALL cp_fm_get_info(gs_mos(1)%mos_occ, ncol_global=na)
     827            0 :          CALL cp_fm_get_info(gs_mos(2)%mos_occ, ncol_global=nb)
     828            0 :          nl = MIN(na, nb)
     829            0 :          nu = MAX(na, nb)
     830              :          ! open shell orbital shift
     831            0 :          DO ispin = 1, n_spins
     832            0 :             coeff => gs_mos(ispin)%mos_occ
     833            0 :             CALL cp_fm_get_info(coeff, matrix_struct=fmstruct, ncol_global=nhomo)
     834            0 :             IF (nhomo == nu) THEN
     835              :                ! downshift with -eos_shift using occupied orbitals
     836            0 :                nos = nu - nl
     837            0 :                CALL cp_fm_create(cmos, fmstruct)
     838            0 :                CALL cp_fm_get_info(coeff, nrow_global=nrow)
     839            0 :                CALL cp_fm_to_fm_submat(coeff, cmos, nrow, nos, 1, nl + 1, 1, 1)
     840            0 :                CALL cp_fm_create(cvec, fmstruct)
     841            0 :                CALL cp_dbcsr_sm_fm_multiply(smat, cmos, cvec, nos, 1.0_dp, 0.0_dp)
     842              :                CALL cp_dbcsr_plus_fm_fm_t(matrix_ks(ispin)%matrix, matrix_v=cvec, ncol=nos, &
     843            0 :                                           alpha=-eos_shift, keep_sparsity=.TRUE.)
     844            0 :                CALL cp_fm_release(cmos)
     845            0 :                CALL cp_fm_release(cvec)
     846              :             ELSE
     847              :                ! upshift with eos_shift using virtual orbitals
     848            0 :                coeff => gs_mos(ispin)%mos_virt
     849            0 :                CALL cp_fm_get_info(coeff, matrix_struct=fmstruct, ncol_global=nvirt)
     850            0 :                nos = nu - nhomo
     851            0 :                CPASSERT(nvirt >= nos)
     852            0 :                CALL cp_fm_create(cvec, fmstruct)
     853            0 :                CALL cp_dbcsr_sm_fm_multiply(smat, coeff, cvec, nos, 1.0_dp, 0.0_dp)
     854              :                CALL cp_dbcsr_plus_fm_fm_t(matrix_ks(ispin)%matrix, matrix_v=cvec, ncol=nos, &
     855            0 :                                           alpha=eos_shift, keep_sparsity=.TRUE.)
     856            0 :                CALL cp_fm_release(cvec)
     857              :             END IF
     858              :          END DO
     859              :          ! virtual shift
     860            0 :          IF (ev_shift /= 0.0_dp) THEN
     861            0 :             DO ispin = 1, n_spins
     862              :                CALL dbcsr_add(matrix_ks(ispin)%matrix, smat, &
     863            0 :                               alpha_scalar=1.0_dp, beta_scalar=ev_shift)
     864            0 :                coeff => gs_mos(ispin)%mos_occ
     865            0 :                CALL cp_fm_get_info(coeff, matrix_struct=fmstruct, ncol_global=nhomo)
     866            0 :                CALL cp_fm_create(cvec, fmstruct)
     867            0 :                CALL cp_dbcsr_sm_fm_multiply(smat, coeff, cvec, nhomo, 1.0_dp, 0.0_dp)
     868              :                CALL cp_dbcsr_plus_fm_fm_t(matrix_ks(ispin)%matrix, matrix_v=cvec, ncol=nhomo, &
     869            0 :                                           alpha=-ev_shift, keep_sparsity=.TRUE.)
     870            0 :                CALL cp_fm_release(cvec)
     871            0 :                IF (nhomo < nu) THEN
     872            0 :                   nos = nu - nhomo
     873            0 :                   coeff => gs_mos(ispin)%mos_virt
     874            0 :                   CALL cp_fm_get_info(coeff, matrix_struct=fmstruct, ncol_global=nvirt)
     875            0 :                   CPASSERT(nvirt >= nos)
     876            0 :                   CALL cp_fm_create(cvec, fmstruct)
     877            0 :                   CALL cp_dbcsr_sm_fm_multiply(smat, coeff, cvec, nos, 1.0_dp, 0.0_dp)
     878              :                   CALL cp_dbcsr_plus_fm_fm_t(matrix_ks(ispin)%matrix, matrix_v=cvec, ncol=nos, &
     879            0 :                                              alpha=-ev_shift, keep_sparsity=.TRUE.)
     880            0 :                   CALL cp_fm_release(cvec)
     881              :                END IF
     882              :             END DO
     883              :          END IF
     884              :       ELSE
     885              :          ! virtual shift
     886           16 :          IF (ev_shift /= 0.0_dp) THEN
     887           16 :             CALL get_qs_env(qs_env, mos=mos, matrix_s=matrix_s)
     888           16 :             smat => matrix_s(1)%matrix
     889           32 :             DO ispin = 1, n_spins
     890              :                CALL dbcsr_add(matrix_ks(ispin)%matrix, smat, &
     891           16 :                               alpha_scalar=1.0_dp, beta_scalar=ev_shift)
     892           16 :                coeff => gs_mos(ispin)%mos_occ
     893           16 :                CALL cp_fm_get_info(coeff, matrix_struct=fmstruct, ncol_global=nhomo)
     894           16 :                CALL cp_fm_create(cvec, fmstruct)
     895           16 :                CALL cp_dbcsr_sm_fm_multiply(smat, coeff, cvec, nhomo, 1.0_dp, 0.0_dp)
     896              :                CALL cp_dbcsr_plus_fm_fm_t(matrix_ks(ispin)%matrix, matrix_v=cvec, ncol=nhomo, &
     897           16 :                                           alpha=-ev_shift, keep_sparsity=.TRUE.)
     898           48 :                CALL cp_fm_release(cvec)
     899              :             END DO
     900              :          END IF
     901              :       END IF
     902              :       ! set eigenvalues
     903           16 :       IF (eos_shift == 0.0_dp .OR. n_spins == 1) THEN
     904           32 :          DO ispin = 1, n_spins
     905           32 :             IF (ALLOCATED(gs_mos(ispin)%evals_virt)) THEN
     906         1332 :                gs_mos(ispin)%evals_virt(:) = gs_mos(ispin)%evals_virt(:) + ev_shift
     907              :             END IF
     908              :          END DO
     909              :       ELSE
     910            0 :          CALL cp_fm_get_info(gs_mos(1)%mos_occ, ncol_global=na)
     911            0 :          CALL cp_fm_get_info(gs_mos(2)%mos_occ, ncol_global=nb)
     912            0 :          nl = MIN(na, nb)
     913            0 :          nu = MAX(na, nb)
     914            0 :          nos = nu - nl
     915            0 :          IF (na == nu) THEN
     916            0 :             IF (ALLOCATED(gs_mos(1)%evals_occ)) THEN
     917            0 :                gs_mos(1)%evals_occ(nl + 1:nu) = gs_mos(1)%evals_occ(nl + 1:nu) - eos_shift
     918              :             END IF
     919            0 :             IF (ALLOCATED(gs_mos(1)%evals_virt)) THEN
     920            0 :                gs_mos(1)%evals_virt(:) = gs_mos(1)%evals_virt(:) + ev_shift
     921              :             END IF
     922            0 :             IF (ALLOCATED(gs_mos(2)%evals_virt)) THEN
     923            0 :                gs_mos(2)%evals_virt(1:nos) = gs_mos(2)%evals_virt(1:nos) + eos_shift
     924            0 :                gs_mos(2)%evals_virt(nos + 1:) = gs_mos(2)%evals_virt(nos + 1:) + ev_shift
     925              :             END IF
     926              :          ELSE
     927            0 :             IF (ALLOCATED(gs_mos(1)%evals_virt)) THEN
     928            0 :                gs_mos(1)%evals_virt(1:nos) = gs_mos(1)%evals_virt(1:nos) + eos_shift
     929            0 :                gs_mos(1)%evals_virt(nos + 1:) = gs_mos(1)%evals_virt(nos + 1:) + ev_shift
     930              :             END IF
     931            0 :             IF (ALLOCATED(gs_mos(2)%evals_occ)) THEN
     932            0 :                gs_mos(2)%evals_occ(nl + 1:nu) = gs_mos(2)%evals_occ(nl + 1:nu) - eos_shift
     933              :             END IF
     934            0 :             IF (ALLOCATED(gs_mos(2)%evals_virt)) THEN
     935            0 :                gs_mos(2)%evals_virt(:) = gs_mos(2)%evals_virt(:) + ev_shift
     936              :             END IF
     937              :          END IF
     938              :       END IF
     939              : 
     940           16 :       CALL timestop(handle)
     941              : 
     942           16 :    END SUBROUTINE ev_shift_operator
     943              : 
     944              : ! **************************************************************************************************
     945              : !> \brief Generate missed guess vectors.
     946              : !> \param evects   guess vectors distributed across all processors (initialised on exit)
     947              : !> \param evals    guessed transition energies (initialised on exit)
     948              : !> \param gs_mos   occupied and virtual molecular orbitals optimised for the ground state
     949              : !> \param log_unit output unit
     950              : !> \param tddfpt_control ...
     951              : !> \param fm_pool_ao_mo_active ...
     952              : !> \param qs_env ...
     953              : !> \param nspins ...
     954              : !> \par History
     955              : !>    * 05.2016 created as tddfpt_guess() [Sergey Chulkov]
     956              : !>    * 06.2016 renamed, altered prototype, supports spin-polarised density [Sergey Chulkov]
     957              : !>    * 01.2017 simplified prototype, do not compute all possible singly-excited states
     958              : !>              [Sergey Chulkov]
     959              : !> \note \parblock
     960              : !>       Based on the subroutine co_initial_guess() which was originally created by
     961              : !>       Thomas Chassaing on 06.2003.
     962              : !>
     963              : !>       Only not associated guess vectors 'evects(spin, state)%matrix' are allocated and
     964              : !>       initialised; associated vectors assumed to be initialised elsewhere (e.g. using
     965              : !>       a restart file).
     966              : !>       \endparblock
     967              : ! **************************************************************************************************
     968         1124 :    SUBROUTINE tddfpt_guess_vectors(evects, evals, gs_mos, log_unit, tddfpt_control, &
     969         1124 :                                    fm_pool_ao_mo_active, qs_env, nspins)
     970              :       TYPE(cp_fm_type), DIMENSION(:, :), INTENT(inout)   :: evects
     971              :       REAL(kind=dp), DIMENSION(:), INTENT(inout)         :: evals
     972              :       INTEGER, INTENT(in)                                :: nspins
     973              :       TYPE(qs_environment_type), INTENT(in), POINTER     :: qs_env
     974              :       TYPE(cp_fm_pool_p_type), DIMENSION(:), INTENT(in)  :: fm_pool_ao_mo_active
     975              :       TYPE(tddfpt2_control_type), INTENT(in), POINTER    :: tddfpt_control
     976              :       INTEGER, INTENT(in)                                :: log_unit
     977              :       TYPE(tddfpt_ground_state_mos), DIMENSION(nspins), &
     978              :          INTENT(in)                                      :: gs_mos
     979              : 
     980              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'tddfpt_guess_vectors'
     981              : 
     982              :       CHARACTER(len=5)                                   :: spin_label1, spin_label2
     983              :       INTEGER :: handle, i, imo_occ, imo_virt, ind, ispin, istate, j, jspin, k, no, nstates, &
     984              :          nstates_occ_virt_alpha, nstates_selected, nv, spin1, spin2
     985         1124 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: inds
     986         1124 :       INTEGER, ALLOCATABLE, DIMENSION(:, :)              :: reverse_index
     987              :       INTEGER, DIMENSION(maxspins)                       :: nmo, nmo_occ_avail, nmo_occ_selected, &
     988              :                                                             nmo_virt_selected
     989              :       REAL(kind=dp)                                      :: e_occ
     990         1124 :       REAL(kind=dp), ALLOCATABLE, DIMENSION(:)           :: e_virt_minus_occ, ev_occ, ev_virt
     991              :       TYPE(excited_energy_type), POINTER                 :: ex_env
     992              : 
     993         1124 :       CALL timeset(routineN, handle)
     994              : 
     995         1124 :       nstates = SIZE(evects, 2)
     996              : 
     997              :       IF (debug_this_module) THEN
     998              :          CPASSERT(nstates > 0)
     999              :          CPASSERT(nspins == 1 .OR. nspins == 2)
    1000              :       END IF
    1001              : 
    1002         1124 :       NULLIFY (ex_env)
    1003         1124 :       CALL get_qs_env(qs_env, exstate_env=ex_env)
    1004              : 
    1005         2400 :       DO ispin = 1, nspins
    1006              :          ! number of occupied orbitals for each spin component
    1007         1276 :          nmo_occ_avail(ispin) = gs_mos(ispin)%nmo_active
    1008         1276 :          nmo(ispin) = gs_mos(ispin)%nmo_occ
    1009              :          ! number of occupied and virtual orbitals which can potentially
    1010              :          ! contribute to the excited states in question.
    1011         1276 :          nmo_occ_selected(ispin) = MIN(nmo_occ_avail(ispin), nstates)
    1012         2400 :          nmo_virt_selected(ispin) = MIN(SIZE(gs_mos(ispin)%evals_virt), nstates)
    1013              :       END DO
    1014              : 
    1015              :       ! TO DO: the variable 'nstates_selected' should probably be declared as INTEGER(kind=int_8),
    1016              :       !        however we need a special version of the subroutine sort() in order to do so
    1017         1124 :       IF (tddfpt_control%spinflip == no_sf_tddfpt) THEN
    1018         2334 :          nstates_selected = DOT_PRODUCT(nmo_occ_selected(1:nspins), nmo_virt_selected(1:nspins))
    1019              :       ELSE
    1020           22 :          nstates_selected = nmo_occ_selected(1)*nmo_virt_selected(2)
    1021              :       END IF
    1022              : 
    1023         3372 :       ALLOCATE (inds(nstates_selected))
    1024         3372 :       ALLOCATE (e_virt_minus_occ(nstates_selected))
    1025              : 
    1026         1124 :       istate = 0
    1027         1124 :       IF (tddfpt_control%spinflip == no_sf_tddfpt) THEN
    1028              :          ! Guess for spin-conserving TDDFT
    1029         2334 :          DO ispin = 1, nspins
    1030         1232 :             no = nmo_occ_selected(ispin)
    1031         1232 :             nv = nmo_virt_selected(ispin)
    1032         6160 :             ALLOCATE (ev_virt(nv), ev_occ(no))
    1033              :             ! if do_bse and do_gw, take gw zeroth order
    1034         1232 :             IF (tddfpt_control%do_bse) THEN
    1035            0 :                ev_virt(1:nv) = ex_env%gw_eigen(nmo(ispin) + 1:nmo(ispin) + nv)
    1036            0 :                DO i = 1, no
    1037            0 :                   j = nmo_occ_avail(ispin) - i + 1
    1038            0 :                   k = gs_mos(ispin)%index_active(j)
    1039            0 :                   ev_occ(i) = ex_env%gw_eigen(k)
    1040              :                END DO
    1041              :             ELSE
    1042         4464 :                ev_virt(1:nv) = gs_mos(ispin)%evals_virt(1:nv)
    1043         4168 :                DO i = 1, no
    1044         2936 :                   j = nmo_occ_avail(ispin) - i + 1
    1045         2936 :                   k = gs_mos(ispin)%index_active(j)
    1046         4168 :                   ev_occ(i) = gs_mos(ispin)%evals_occ(k)
    1047              :                END DO
    1048              :             END IF
    1049              : 
    1050         4168 :             DO imo_occ = 1, nmo_occ_selected(ispin)
    1051              :                ! Here imo_occ enumerate Occupied orbitals in inverse order (from the last to the first element)
    1052         2936 :                e_occ = ev_occ(imo_occ)
    1053              :                !
    1054        14508 :                DO imo_virt = 1, nmo_virt_selected(ispin)
    1055        10340 :                   istate = istate + 1
    1056        13276 :                   e_virt_minus_occ(istate) = ev_virt(imo_virt) - e_occ
    1057              :                END DO
    1058              :             END DO
    1059              : 
    1060         2334 :             DEALLOCATE (ev_virt, ev_occ)
    1061              :          END DO
    1062              :       ELSE
    1063              :          ! Guess for spin-flip TDDFT
    1064          112 :          DO imo_occ = 1, nmo_occ_selected(1)
    1065              :             ! Here imo_occ enumerate alpha Occupied orbitals in inverse order (from the last to the first element)
    1066           90 :             i = gs_mos(1)%nmo_active - imo_occ + 1
    1067           90 :             k = gs_mos(1)%index_active(i)
    1068           90 :             e_occ = gs_mos(1)%evals_occ(k)
    1069              : 
    1070          502 :             DO imo_virt = 1, nmo_virt_selected(2)
    1071          390 :                istate = istate + 1
    1072          480 :                e_virt_minus_occ(istate) = gs_mos(2)%evals_virt(imo_virt) - e_occ
    1073              :             END DO
    1074              :          END DO
    1075              :       END IF
    1076              : 
    1077              :       IF (debug_this_module) THEN
    1078              :          CPASSERT(istate == nstates_selected)
    1079              :       END IF
    1080              : 
    1081         1124 :       CALL sort(e_virt_minus_occ, nstates_selected, inds)
    1082              : 
    1083              :       ! Labels and spin component for closed-shell
    1084         1124 :       IF (nspins == 1) THEN
    1085          972 :          spin1 = 1
    1086          972 :          spin2 = spin1
    1087          972 :          spin_label1 = '     '
    1088          972 :          spin_label2 = spin_label1
    1089              :          ! Labels and spin component for spin-flip excitations
    1090          152 :       ELSE IF (tddfpt_control%spinflip /= no_sf_tddfpt) THEN
    1091           22 :          spin1 = 1
    1092           22 :          spin2 = 2
    1093           22 :          spin_label1 = '(alp)'
    1094           22 :          spin_label2 = '(bet)'
    1095              :       END IF
    1096              : 
    1097         1124 :       IF (tddfpt_control%spinflip == no_sf_tddfpt) THEN
    1098              :          ! Calculate maximum number of alpha excitations
    1099         1102 :          nstates_occ_virt_alpha = nmo_occ_selected(1)*nmo_virt_selected(1)
    1100              :       ELSE
    1101              :          ! Calculate maximum number of spin-flip excitations
    1102           22 :          nstates_occ_virt_alpha = nmo_occ_selected(1)*nmo_virt_selected(2)
    1103              :       END IF
    1104         1124 :       IF (log_unit > 0) THEN
    1105          562 :          WRITE (log_unit, "(1X,A)") "", &
    1106          562 :             "-------------------------------------------------------------------------------", &
    1107          562 :             "-                            TDDFPT Initial Guess                             -", &
    1108         1124 :             "-------------------------------------------------------------------------------"
    1109          562 :          WRITE (log_unit, '(T11,A)') "State         Occupied      ->      Virtual          Excitation"
    1110          562 :          WRITE (log_unit, '(T11,A)') "number         orbital              orbital          energy (eV)"
    1111          562 :          WRITE (log_unit, '(1X,79("-"))')
    1112              :       END IF
    1113              : 
    1114         3372 :       i = MAXVAL(nmo(:))
    1115         4496 :       ALLOCATE (reverse_index(i, nspins))
    1116         9220 :       reverse_index = 0
    1117         2400 :       DO ispin = 1, nspins
    1118         9074 :          DO i = 1, SIZE(gs_mos(ispin)%index_active)
    1119         6674 :             j = gs_mos(ispin)%index_active(i)
    1120         7950 :             reverse_index(j, ispin) = i
    1121              :          END DO
    1122              :       END DO
    1123              : 
    1124         4198 :       DO istate = 1, nstates
    1125         4198 :          IF (ASSOCIATED(evects(1, istate)%matrix_struct)) THEN
    1126              :             ! Initial guess vector read from restart file
    1127            6 :             IF (log_unit > 0) &
    1128              :                WRITE (log_unit, '(T7,I8,T28,A19,T60,F14.5)') &
    1129            3 :                istate, "***  restarted  ***", evals(istate)*evolt
    1130              :          ELSE
    1131              :             ! New initial guess vector
    1132              :             !
    1133              :             ! Index of excited state - 1
    1134         3068 :             ind = inds(istate) - 1
    1135              : 
    1136              :             ! Labels and spin component for open-shell spin-conserving excitations
    1137         3068 :             IF ((nspins > 1) .AND. (tddfpt_control%spinflip == no_sf_tddfpt)) THEN
    1138          398 :                IF (ind < nstates_occ_virt_alpha) THEN
    1139          166 :                   spin1 = 1
    1140          166 :                   spin2 = 1
    1141          166 :                   spin_label1 = '(alp)'
    1142          166 :                   spin_label2 = '(alp)'
    1143              :                ELSE
    1144          232 :                   ind = ind - nstates_occ_virt_alpha
    1145          232 :                   spin1 = 2
    1146          232 :                   spin2 = 2
    1147          232 :                   spin_label1 = '(bet)'
    1148          232 :                   spin_label2 = '(bet)'
    1149              :                END IF
    1150              :             END IF
    1151              : 
    1152              :             ! Recover index of occupied MO (imo_occ) and unoccupied MO (imo_virt)
    1153              :             ! associated to the excited state index (ind+1)
    1154         3068 :             i = ind/nmo_virt_selected(spin2) + 1
    1155         3068 :             j = nmo_occ_avail(spin1) - i + 1
    1156         3068 :             imo_occ = gs_mos(spin1)%index_active(j)
    1157         3068 :             imo_virt = MOD(ind, nmo_virt_selected(spin2)) + 1
    1158              :             ! Assign initial guess for excitation energy
    1159         3068 :             evals(istate) = e_virt_minus_occ(istate)
    1160              : 
    1161         3068 :             IF (log_unit > 0) &
    1162              :                WRITE (log_unit, '(T7,I8,T24,I8,T37,A5,T45,I8,T54,A5,T60,F14.5)') &
    1163         1534 :                istate, imo_occ, spin_label1, nmo(spin2) + imo_virt, spin_label2, e_virt_minus_occ(istate)*evolt
    1164              : 
    1165         6534 :             DO jspin = 1, SIZE(evects, 1)
    1166              :                ! .NOT. ASSOCIATED(evects(jspin, istate)%matrix_struct))
    1167         3466 :                CALL fm_pool_create_fm(fm_pool_ao_mo_active(jspin)%pool, evects(jspin, istate))
    1168         3466 :                CALL cp_fm_set_all(evects(jspin, istate), 0.0_dp)
    1169              : 
    1170         6534 :                IF (jspin == spin1) THEN
    1171              :                   ! Half transform excitation vector to ao space:
    1172              :                   ! evects_mi = c_ma*X_ai
    1173         3068 :                   i = reverse_index(imo_occ, spin1)
    1174              :                   CALL cp_fm_to_fm(gs_mos(spin2)%mos_virt, evects(spin1, istate), &
    1175         3068 :                                    ncol=1, source_start=imo_virt, target_start=i)
    1176              :                END IF
    1177              :             END DO
    1178              :          END IF
    1179              :       END DO
    1180              : 
    1181         1124 :       DEALLOCATE (reverse_index)
    1182              : 
    1183         1124 :       IF (log_unit > 0) THEN
    1184          562 :          WRITE (log_unit, '(/,T7,A,T50,I24)') 'Number of active states:', &
    1185         1124 :             tddfpt_total_number_of_states(tddfpt_control, gs_mos)
    1186              :          WRITE (log_unit, "(1X,A)") &
    1187          562 :             "-------------------------------------------------------------------------------"
    1188              :       END IF
    1189              : 
    1190         1124 :       DEALLOCATE (e_virt_minus_occ)
    1191         1124 :       DEALLOCATE (inds)
    1192              : 
    1193         1124 :       CALL timestop(handle)
    1194              : 
    1195         2248 :    END SUBROUTINE tddfpt_guess_vectors
    1196              : 
    1197              : END MODULE qs_tddfpt2_utils
        

Generated by: LCOV version 2.0-1