LCOV - code coverage report
Current view: top level - src - qs_tddfpt2_utils.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:2fce0f8) Lines: 332 458 72.5 %
Date: 2024-12-21 06:28:57 Functions: 7 7 100.0 %

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

Generated by: LCOV version 1.15