LCOV - code coverage report
Current view: top level - src - qs_tddfpt2_restart.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:936074a) Lines: 78.4 % 241 189
Test Date: 2025-12-04 06:27:48 Functions: 80.0 % 5 4

            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_restart
       9              :    USE cp_blacs_env,                    ONLY: cp_blacs_env_type
      10              :    USE cp_dbcsr_api,                    ONLY: dbcsr_type
      11              :    USE cp_dbcsr_operations,             ONLY: cp_dbcsr_sm_fm_multiply
      12              :    USE cp_files,                        ONLY: close_file,&
      13              :                                               open_file
      14              :    USE cp_fm_basic_linalg,              ONLY: cp_fm_column_scale,&
      15              :                                               cp_fm_scale_and_add,&
      16              :                                               cp_fm_trace
      17              :    USE cp_fm_pool_types,                ONLY: cp_fm_pool_p_type,&
      18              :                                               fm_pool_create_fm,&
      19              :                                               fm_pool_give_back_fm
      20              :    USE cp_fm_struct,                    ONLY: cp_fm_struct_create,&
      21              :                                               cp_fm_struct_release,&
      22              :                                               cp_fm_struct_type
      23              :    USE cp_fm_types,                     ONLY: cp_fm_create,&
      24              :                                               cp_fm_get_info,&
      25              :                                               cp_fm_read_unformatted,&
      26              :                                               cp_fm_release,&
      27              :                                               cp_fm_type,&
      28              :                                               cp_fm_write_formatted,&
      29              :                                               cp_fm_write_info,&
      30              :                                               cp_fm_write_unformatted
      31              :    USE cp_log_handling,                 ONLY: cp_logger_type
      32              :    USE cp_output_handling,              ONLY: cp_p_file,&
      33              :                                               cp_print_key_finished_output,&
      34              :                                               cp_print_key_generate_filename,&
      35              :                                               cp_print_key_should_output,&
      36              :                                               cp_print_key_unit_nr
      37              :    USE input_section_types,             ONLY: section_vals_get_subs_vals,&
      38              :                                               section_vals_type,&
      39              :                                               section_vals_val_get
      40              :    USE kinds,                           ONLY: default_path_length,&
      41              :                                               dp
      42              :    USE message_passing,                 ONLY: mp_para_env_type
      43              :    USE parallel_gemm_api,               ONLY: parallel_gemm
      44              :    USE qs_tddfpt2_subgroups,            ONLY: tddfpt_subgroup_env_type
      45              :    USE qs_tddfpt2_types,                ONLY: tddfpt_ground_state_mos
      46              :    USE string_utilities,                ONLY: integer_to_string
      47              : #include "./base/base_uses.f90"
      48              : 
      49              :    IMPLICIT NONE
      50              : 
      51              :    PRIVATE
      52              : 
      53              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_tddfpt2_restart'
      54              : 
      55              :    LOGICAL, PARAMETER, PRIVATE          :: debug_this_module = .FALSE.
      56              :    ! number of first derivative components (3: d/dx, d/dy, d/dz)
      57              :    INTEGER, PARAMETER, PRIVATE          :: nderivs = 3
      58              :    INTEGER, PARAMETER, PRIVATE          :: maxspins = 2
      59              : 
      60              :    PUBLIC :: tddfpt_write_restart, tddfpt_read_restart, tddfpt_write_newtonx_output, tddfpt_check_orthonormality
      61              : 
      62              : ! **************************************************************************************************
      63              : 
      64              : CONTAINS
      65              : 
      66              : ! **************************************************************************************************
      67              : !> \brief Write Ritz vectors to a binary restart file.
      68              : !> \param evects               vectors to store
      69              : !> \param evals                TDDFPT eigenvalues
      70              : !> \param gs_mos               structure that holds ground state occupied and virtual
      71              : !>                             molecular orbitals
      72              : !> \param logger               a logger object
      73              : !> \param tddfpt_print_section TDDFPT%PRINT input section
      74              : !> \par History
      75              : !>    * 08.2016 created [Sergey Chulkov]
      76              : ! **************************************************************************************************
      77         6556 :    SUBROUTINE tddfpt_write_restart(evects, evals, gs_mos, logger, tddfpt_print_section)
      78              :       TYPE(cp_fm_type), DIMENSION(:, :), INTENT(in)      :: evects
      79              :       REAL(kind=dp), DIMENSION(:), INTENT(in)            :: evals
      80              :       TYPE(tddfpt_ground_state_mos), DIMENSION(:), &
      81              :          INTENT(in)                                      :: gs_mos
      82              :       TYPE(cp_logger_type), POINTER                      :: logger
      83              :       TYPE(section_vals_type), POINTER                   :: tddfpt_print_section
      84              : 
      85              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'tddfpt_write_restart'
      86              : 
      87              :       INTEGER                                            :: handle, ispin, istate, nao, nspins, &
      88              :                                                             nstates, ounit
      89              :       INTEGER, DIMENSION(maxspins)                       :: nmo_active
      90              : 
      91         6556 :       IF (BTEST(cp_print_key_should_output(logger%iter_info, tddfpt_print_section, "RESTART"), cp_p_file)) THEN
      92         1160 :          CALL timeset(routineN, handle)
      93              : 
      94         1160 :          nspins = SIZE(evects, 1)
      95         1160 :          nstates = SIZE(evects, 2)
      96              : 
      97              :          IF (debug_this_module) THEN
      98              :             CPASSERT(SIZE(evals) == nstates)
      99              :             CPASSERT(nspins > 0)
     100              :             CPASSERT(nstates > 0)
     101              :          END IF
     102              : 
     103         1160 :          CALL cp_fm_get_info(evects(1, 1), nrow_global=nao)
     104         2450 :          DO ispin = 1, nspins
     105         2450 :             CALL cp_fm_get_info(evects(ispin, 1), ncol_global=nmo_active(ispin))
     106              :          END DO
     107              : 
     108              :          ounit = cp_print_key_unit_nr(logger, tddfpt_print_section, "RESTART", &
     109              :                                       extension=".tdwfn", file_status="REPLACE", file_action="WRITE", &
     110         1160 :                                       do_backup=.TRUE., file_form="UNFORMATTED")
     111              : 
     112         1160 :          IF (ounit > 0) THEN
     113          580 :             WRITE (ounit) nstates, nspins, nao
     114          580 :             WRITE (ounit) nmo_active(1:nspins)
     115          580 :             WRITE (ounit) evals
     116              :          END IF
     117              : 
     118         4294 :          DO istate = 1, nstates
     119         7832 :             DO ispin = 1, nspins
     120              :                ! TDDFPT wave function is actually stored as a linear combination of virtual MOs
     121              :                ! that replaces the corresponding deoccupied MO. Unfortunately, the phase
     122              :                ! of the occupied MOs varies depending on the eigensolver used as well as
     123              :                ! how eigenvectors are distributed across computational cores. The phase is important
     124              :                ! because TDDFPT wave functions are used to compute a response electron density
     125              :                ! \rho^{-} = 1/2 * [C_{0} * evect^T + evect * C_{0}^{-}], where C_{0} is the expansion
     126              :                ! coefficients of the reference ground-state wave function. To make the restart file
     127              :                ! transferable, TDDFPT wave functions are stored in assumption that all ground state
     128              :                ! MOs have a positive phase.
     129         3538 :                CALL cp_fm_column_scale(evects(ispin, istate), gs_mos(ispin)%phases_occ)
     130              : 
     131         3538 :                CALL cp_fm_write_unformatted(evects(ispin, istate), ounit)
     132              : 
     133         6672 :                CALL cp_fm_column_scale(evects(ispin, istate), gs_mos(ispin)%phases_occ)
     134              :             END DO
     135              :          END DO
     136              : 
     137         1160 :          CALL cp_print_key_finished_output(ounit, logger, tddfpt_print_section, "RESTART")
     138              : 
     139         1160 :          CALL timestop(handle)
     140              :       END IF
     141              : 
     142         6556 :    END SUBROUTINE tddfpt_write_restart
     143              : 
     144              : ! **************************************************************************************************
     145              : !> \brief Initialise initial guess vectors by reading (un-normalised) Ritz vectors
     146              : !>        from a binary restart file.
     147              : !> \param evects               vectors to initialise (initialised on exit)
     148              : !> \param evals                TDDFPT eigenvalues (initialised on exit)
     149              : !> \param gs_mos               structure that holds ground state occupied and virtual
     150              : !>                             molecular orbitals
     151              : !> \param logger               a logger object
     152              : !> \param tddfpt_section       TDDFPT input section
     153              : !> \param tddfpt_print_section TDDFPT%PRINT input section
     154              : !> \param fm_pool_ao_mo_active pools of dense matrices with shape [nao x nmo_active(spin)]
     155              : !> \param blacs_env_global     BLACS parallel environment involving all the processor
     156              : !> \return the number of excited states found in the restart file
     157              : !> \par History
     158              : !>    * 08.2016 created [Sergey Chulkov]
     159              : ! **************************************************************************************************
     160           12 :    FUNCTION tddfpt_read_restart(evects, evals, gs_mos, logger, tddfpt_section, tddfpt_print_section, &
     161            6 :                                 fm_pool_ao_mo_active, blacs_env_global) RESULT(nstates_read)
     162              :       TYPE(cp_fm_type), DIMENSION(:, :), INTENT(inout)   :: evects
     163              :       REAL(kind=dp), DIMENSION(:), INTENT(out)           :: evals
     164              :       TYPE(tddfpt_ground_state_mos), DIMENSION(:), &
     165              :          INTENT(in)                                      :: gs_mos
     166              :       TYPE(cp_logger_type), POINTER                      :: logger
     167              :       TYPE(section_vals_type), POINTER                   :: tddfpt_section, tddfpt_print_section
     168              :       TYPE(cp_fm_pool_p_type), DIMENSION(:), INTENT(in)  :: fm_pool_ao_mo_active
     169              :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env_global
     170              :       INTEGER                                            :: nstates_read
     171              : 
     172              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'tddfpt_read_restart'
     173              : 
     174              :       CHARACTER(len=20)                                  :: read_str, ref_str
     175              :       CHARACTER(LEN=default_path_length)                 :: filename
     176              :       INTEGER                                            :: handle, ispin, istate, iunit, n_rep_val, &
     177              :                                                             nao, nao_read, nspins, nspins_read, &
     178              :                                                             nstates
     179              :       INTEGER, DIMENSION(maxspins)                       :: nmo_active, nmo_active_read
     180              :       LOGICAL                                            :: file_exists
     181            6 :       REAL(kind=dp), ALLOCATABLE, DIMENSION(:)           :: evals_read
     182              :       TYPE(cp_fm_type)                                   :: evtest
     183              :       TYPE(mp_para_env_type), POINTER                    :: para_env_global
     184              :       TYPE(section_vals_type), POINTER                   :: print_key
     185              : 
     186            6 :       CALL timeset(routineN, handle)
     187              : 
     188            6 :       CPASSERT(ASSOCIATED(tddfpt_section))
     189              : 
     190              :       ! generate restart file name
     191            6 :       CALL section_vals_val_get(tddfpt_section, "WFN_RESTART_FILE_NAME", n_rep_val=n_rep_val)
     192            6 :       IF (n_rep_val > 0) THEN
     193            0 :          CALL section_vals_val_get(tddfpt_section, "WFN_RESTART_FILE_NAME", c_val=filename)
     194              :       ELSE
     195            6 :          print_key => section_vals_get_subs_vals(tddfpt_print_section, "RESTART")
     196              :          filename = cp_print_key_generate_filename(logger, print_key, &
     197            6 :                                                    extension=".tdwfn", my_local=.FALSE.)
     198              :       END IF
     199              : 
     200            6 :       CALL blacs_env_global%get(para_env=para_env_global)
     201              : 
     202            6 :       IF (para_env_global%is_source()) THEN
     203            3 :          INQUIRE (FILE=filename, exist=file_exists)
     204              : 
     205            3 :          IF (.NOT. file_exists) THEN
     206            2 :             nstates_read = 0
     207            2 :             CALL para_env_global%bcast(nstates_read)
     208              : 
     209              :             CALL cp_warn(__LOCATION__, &
     210              :                          "User requested to restart the TDDFPT wave functions from the file '"//TRIM(filename)// &
     211            2 :                          "' which does not exist. Guess wave functions will be constructed using Kohn-Sham orbitals.")
     212            2 :             CALL timestop(handle)
     213            2 :             RETURN
     214              :          END IF
     215              : 
     216              :          CALL open_file(file_name=filename, file_action="READ", file_form="UNFORMATTED", &
     217            1 :                         file_status="OLD", unit_number=iunit)
     218              :       END IF
     219              : 
     220            4 :       nspins = SIZE(evects, 1)
     221            4 :       nstates = SIZE(evects, 2)
     222              : 
     223           12 :       DO ispin = 1, nspins
     224            8 :          CALL fm_pool_create_fm(fm_pool_ao_mo_active(ispin)%pool, evtest)
     225            8 :          CALL cp_fm_get_info(evtest, nrow_global=nao, ncol_global=nmo_active(ispin))
     226           12 :          CALL fm_pool_give_back_fm(fm_pool_ao_mo_active(ispin)%pool, evtest)
     227              :       END DO
     228              : 
     229            4 :       IF (para_env_global%is_source()) THEN
     230            1 :          READ (iunit) nstates_read, nspins_read, nao_read
     231              : 
     232            1 :          IF (nspins_read /= nspins) THEN
     233            0 :             CALL integer_to_string(nspins, ref_str)
     234            0 :             CALL integer_to_string(nspins_read, read_str)
     235              :             CALL cp_abort(__LOCATION__, &
     236              :                           "Restarted TDDFPT wave function contains incompatible number of spin components ("// &
     237            0 :                           TRIM(read_str)//" instead of "//TRIM(ref_str)//").")
     238              :          END IF
     239              : 
     240            1 :          IF (nao_read /= nao) THEN
     241            0 :             CALL integer_to_string(nao, ref_str)
     242            0 :             CALL integer_to_string(nao_read, read_str)
     243              :             CALL cp_abort(__LOCATION__, &
     244            0 :                           "Incompatible number of atomic orbitals ("//TRIM(read_str)//" instead of "//TRIM(ref_str)//").")
     245              :          END IF
     246              : 
     247            1 :          READ (iunit) nmo_active_read(1:nspins)
     248              : 
     249            3 :          DO ispin = 1, nspins
     250            3 :             IF (nmo_active_read(ispin) /= nmo_active(ispin)) THEN
     251              :                CALL cp_abort(__LOCATION__, &
     252            0 :                              "Incompatible number of electrons and/or multiplicity.")
     253              :             END IF
     254              :          END DO
     255              : 
     256            1 :          IF (nstates_read /= nstates) THEN
     257            0 :             CALL integer_to_string(nstates, ref_str)
     258            0 :             CALL integer_to_string(nstates_read, read_str)
     259              :             CALL cp_warn(__LOCATION__, &
     260              :                          "TDDFPT restart file contains "//TRIM(read_str)// &
     261              :                          " wave function(s) however "//TRIM(ref_str)// &
     262            0 :                          " excited states were requested.")
     263              :          END IF
     264              :       END IF
     265            4 :       CALL para_env_global%bcast(nstates_read)
     266              : 
     267              :       ! exit if restart file does not exist
     268            4 :       IF (nstates_read <= 0) THEN
     269            2 :          CALL timestop(handle)
     270            2 :          RETURN
     271              :       END IF
     272              : 
     273            2 :       IF (para_env_global%is_source()) THEN
     274            3 :          ALLOCATE (evals_read(nstates_read))
     275            1 :          READ (iunit) evals_read
     276            1 :          IF (nstates_read <= nstates) THEN
     277            4 :             evals(1:nstates_read) = evals_read(1:nstates_read)
     278              :          ELSE
     279            0 :             evals(1:nstates) = evals_read(1:nstates)
     280              :          END IF
     281            1 :          DEALLOCATE (evals_read)
     282              :       END IF
     283           14 :       CALL para_env_global%bcast(evals)
     284              : 
     285            8 :       DO istate = 1, nstates_read
     286           20 :          DO ispin = 1, nspins
     287           18 :             IF (istate <= nstates) THEN
     288           12 :                CALL fm_pool_create_fm(fm_pool_ao_mo_active(ispin)%pool, evects(ispin, istate))
     289              : 
     290           12 :                CALL cp_fm_read_unformatted(evects(ispin, istate), iunit)
     291              : 
     292           12 :                CALL cp_fm_column_scale(evects(ispin, istate), gs_mos(ispin)%phases_occ)
     293              :             END IF
     294              :          END DO
     295              :       END DO
     296              : 
     297            2 :       IF (para_env_global%is_source()) &
     298            1 :          CALL close_file(unit_number=iunit)
     299              : 
     300            2 :       CALL timestop(handle)
     301              : 
     302           12 :    END FUNCTION tddfpt_read_restart
     303              : ! **************************************************************************************************
     304              : !> \brief Write Ritz vectors to a binary restart file.
     305              : !> \param evects               vectors to store
     306              : !> \param evals                TDDFPT eigenvalues
     307              : !> \param gs_mos               structure that holds ground state occupied and virtual
     308              : !>                             molecular orbitals
     309              : !> \param logger               a logger object
     310              : !> \param tddfpt_print_section TDDFPT%PRINT input section
     311              : !> \param matrix_s ...
     312              : !> \param S_evects ...
     313              : !> \param sub_env ...
     314              : ! **************************************************************************************************
     315            2 :    SUBROUTINE tddfpt_write_newtonx_output(evects, evals, gs_mos, logger, tddfpt_print_section, &
     316            2 :                                           matrix_s, S_evects, sub_env)
     317              : 
     318              :       TYPE(cp_fm_type), DIMENSION(:, :), INTENT(in)      :: evects
     319              :       REAL(kind=dp), DIMENSION(:), INTENT(in)            :: evals
     320              :       TYPE(tddfpt_ground_state_mos), DIMENSION(:), &
     321              :          INTENT(in)                                      :: gs_mos
     322              :       TYPE(cp_logger_type), INTENT(in), POINTER          :: logger
     323              :       TYPE(section_vals_type), INTENT(in), POINTER       :: tddfpt_print_section
     324              :       TYPE(dbcsr_type), INTENT(in), POINTER              :: matrix_s
     325              :       TYPE(cp_fm_type), DIMENSION(:, :), INTENT(INOUT)   :: S_evects
     326              :       TYPE(tddfpt_subgroup_env_type), INTENT(in)         :: sub_env
     327              : 
     328              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'tddfpt_write_newtonx_output'
     329              : 
     330              :       INTEGER                                            :: handle, iocc, ispin, istate, ivirt, nao, &
     331              :                                                             nspins, nstates, ounit
     332              :       INTEGER, DIMENSION(maxspins)                       :: nmo_active, nmo_occ, nmo_virt
     333              :       LOGICAL                                            :: print_phases, print_virtuals, &
     334              :                                                             scale_with_phases
     335            2 :       REAL(kind=dp), ALLOCATABLE, DIMENSION(:)           :: phase_evects
     336              :       TYPE(cp_fm_struct_type), POINTER                   :: fmstruct
     337            2 :       TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:, :)     :: evects_mo
     338              : 
     339            2 :       IF (BTEST(cp_print_key_should_output(logger%iter_info, tddfpt_print_section, "NAMD_PRINT"), cp_p_file)) THEN
     340            2 :          CALL timeset(routineN, handle)
     341            2 :          CALL section_vals_val_get(tddfpt_print_section, "NAMD_PRINT%PRINT_VIRTUALS", l_val=print_virtuals)
     342            2 :          CALL section_vals_val_get(tddfpt_print_section, "NAMD_PRINT%PRINT_PHASES", l_val=print_phases)
     343            2 :          CALL section_vals_val_get(tddfpt_print_section, "NAMD_PRINT%SCALE_WITH_PHASES", l_val=scale_with_phases)
     344              : 
     345            2 :          nspins = SIZE(evects, 1)
     346            2 :          nstates = SIZE(evects, 2)
     347              : 
     348              :          IF (debug_this_module) THEN
     349              :             CPASSERT(SIZE(evals) == nstates)
     350              :             CPASSERT(nspins > 0)
     351              :             CPASSERT(nstates > 0)
     352              :          END IF
     353              : 
     354            2 :          CALL cp_fm_get_info(gs_mos(1)%mos_occ, nrow_global=nao)
     355              : 
     356            2 :          IF (sub_env%is_split) THEN
     357              :             CALL cp_abort(__LOCATION__, "NEWTONX interface print not possible when states"// &
     358            0 :                           " are distributed to different CPU pools.")
     359              :          END IF
     360              : 
     361              :          ! test for reduced active orbitals
     362            4 :          DO ispin = 1, nspins
     363            2 :             nmo_occ(ispin) = SIZE(gs_mos(ispin)%evals_occ)
     364            2 :             CALL cp_fm_get_info(evects(ispin, 1), ncol_global=nmo_active(ispin))
     365            4 :             IF (nmo_occ(ispin) /= nmo_active(ispin)) THEN
     366              :                CALL cp_abort(__LOCATION__, "NEWTONX interface print not possible when using"// &
     367            0 :                              " a reduced set of active occupied orbitals.")
     368              :             END IF
     369              :          END DO
     370              : 
     371              :          ounit = cp_print_key_unit_nr(logger, tddfpt_print_section, "NAMD_PRINT", &
     372            2 :                                       extension=".inp", file_form="FORMATTED", file_action="WRITE", file_status="REPLACE")
     373              :          IF (debug_this_module) CALL tddfpt_check_orthonormality(evects, ounit, S_evects, matrix_s)
     374              : 
     375              :          ! print eigenvectors
     376            2 :          IF (print_virtuals) THEN
     377           12 :             ALLOCATE (evects_mo(nspins, nstates))
     378            4 :             DO istate = 1, nstates
     379            6 :                DO ispin = 1, nspins
     380              : 
     381              :                   ! transform eigenvectors
     382            2 :                   NULLIFY (fmstruct)
     383            2 :                   nmo_occ(ispin) = SIZE(gs_mos(ispin)%evals_occ)
     384            2 :                   nmo_virt(ispin) = SIZE(gs_mos(ispin)%evals_virt)
     385              :                   CALL cp_fm_struct_create(fmstruct, para_env=sub_env%para_env, &
     386              :                                            context=sub_env%blacs_env, &
     387            2 :                                            nrow_global=nmo_virt(ispin), ncol_global=nmo_occ(ispin))
     388            2 :                   CALL cp_fm_create(evects_mo(ispin, istate), fmstruct)
     389            2 :                   CALL cp_fm_struct_release(fmstruct)
     390              :                   CALL cp_dbcsr_sm_fm_multiply(matrix_s, evects(ispin, istate), S_evects(ispin, istate), &
     391            4 :                                                ncol=nmo_occ(ispin), alpha=1.0_dp, beta=0.0_dp)
     392              :                END DO
     393              :             END DO
     394            4 :             DO istate = 1, nstates
     395            6 :                DO ispin = 1, nspins
     396              :                   CALL parallel_gemm("T", "N", &
     397              :                                      nmo_virt(ispin), &
     398              :                                      nmo_occ(ispin), &
     399              :                                      nao, &
     400              :                                      1.0_dp, &
     401              :                                      gs_mos(ispin)%mos_virt, &
     402              :                                      S_evects(ispin, istate), & !this also needs to be orthogonalized
     403              :                                      0.0_dp, &
     404            4 :                                      evects_mo(ispin, istate))
     405              :                END DO
     406              :             END DO
     407              :          END IF
     408              : 
     409            4 :          DO istate = 1, nstates
     410            6 :             DO ispin = 1, nspins
     411              : 
     412            2 :                IF (.NOT. print_virtuals) THEN
     413            0 :                   CALL cp_fm_column_scale(evects(ispin, istate), gs_mos(ispin)%phases_occ)
     414            0 :                   IF (ounit > 0) THEN
     415            0 :                      WRITE (ounit, "(/,A)") "ES EIGENVECTORS SIZE"
     416            0 :                      CALL cp_fm_write_info(evects(ispin, istate), ounit)
     417              :                   END IF
     418            0 :                   CALL cp_fm_write_formatted(evects(ispin, istate), ounit, "ES EIGENVECTORS")
     419              :                ELSE
     420            2 :                   CALL cp_fm_column_scale(evects_mo(ispin, istate), gs_mos(ispin)%phases_occ)
     421            2 :                   IF (ounit > 0) THEN
     422            1 :                      WRITE (ounit, "(/,A)") "ES EIGENVECTORS SIZE"
     423            1 :                      CALL cp_fm_write_info(evects_mo(ispin, istate), ounit)
     424              :                   END IF
     425            2 :                   CALL cp_fm_write_formatted(evects_mo(ispin, istate), ounit, "ES EIGENVECTORS")
     426              :                END IF
     427              : 
     428              :                ! compute and print phase of eigenvectors
     429            2 :                nmo_occ(ispin) = SIZE(gs_mos(ispin)%evals_occ)
     430            6 :                ALLOCATE (phase_evects(nmo_occ(ispin)))
     431            2 :                IF (print_virtuals) THEN
     432            2 :                   CALL compute_phase_eigenvectors(evects_mo(ispin, istate), phase_evects, sub_env)
     433              :                ELSE
     434            0 :                   CALL compute_phase_eigenvectors(evects(ispin, istate), phase_evects, sub_env)
     435              :                END IF
     436            2 :                IF (ounit > 0) THEN
     437            1 :                   WRITE (ounit, "(/,A,/)") "PHASES ES EIGENVECTORS"
     438            5 :                   DO iocc = 1, nmo_occ(ispin)
     439            5 :                      WRITE (ounit, "(F20.14)") phase_evects(iocc)
     440              :                   END DO
     441              :                END IF
     442            4 :                DEALLOCATE (phase_evects)
     443              : 
     444              :             END DO
     445              :          END DO
     446              : 
     447            2 :          IF (print_virtuals) THEN
     448            2 :             CALL cp_fm_release(evects_mo)
     449              :          END IF
     450              : 
     451            4 :          DO ispin = 1, nspins
     452            2 :             IF (ounit > 0) THEN
     453            1 :                WRITE (ounit, "(/,A)") "OCCUPIED MOS SIZE"
     454            1 :                CALL cp_fm_write_info(gs_mos(ispin)%mos_occ, ounit)
     455              :             END IF
     456            4 :             CALL cp_fm_write_formatted(gs_mos(ispin)%mos_occ, ounit, "OCCUPIED MO COEFFICIENTS")
     457              :          END DO
     458              : 
     459            2 :          IF (ounit > 0) THEN
     460            1 :             WRITE (ounit, "(A)") "OCCUPIED MO EIGENVALUES"
     461            2 :             DO ispin = 1, nspins
     462            1 :                nmo_occ(ispin) = SIZE(gs_mos(ispin)%evals_occ)
     463            6 :                DO iocc = 1, nmo_occ(ispin)
     464            5 :                   WRITE (ounit, "(F20.14)") gs_mos(ispin)%evals_occ(iocc)
     465              :                END DO
     466              :             END DO
     467              :          END IF
     468              : !
     469            2 :          IF (print_virtuals) THEN
     470            4 :             DO ispin = 1, nspins
     471            2 :                IF (ounit > 0) THEN
     472            1 :                   WRITE (ounit, "(/,A)") "VIRTUAL MOS SIZE"
     473            1 :                   CALL cp_fm_write_info(gs_mos(ispin)%mos_virt, ounit)
     474              :                END IF
     475            4 :                CALL cp_fm_write_formatted(gs_mos(ispin)%mos_virt, ounit, "VIRTUAL MO COEFFICIENTS")
     476              :             END DO
     477              : 
     478            2 :             IF (ounit > 0) THEN
     479            1 :                WRITE (ounit, "(A)") "VIRTUAL MO EIGENVALUES"
     480            2 :                DO ispin = 1, nspins
     481            1 :                   nmo_virt(ispin) = SIZE(gs_mos(ispin)%evals_virt)
     482           21 :                   DO ivirt = 1, nmo_virt(ispin)
     483           20 :                      WRITE (ounit, "(F20.14)") gs_mos(ispin)%evals_virt(ivirt)
     484              :                   END DO
     485              :                END DO
     486              :             END IF
     487              :          END IF
     488              : 
     489              :          ! print phases of molecular orbitals
     490              : 
     491            2 :          IF (print_phases) THEN
     492            0 :             IF (ounit > 0) THEN
     493            0 :                WRITE (ounit, "(A)") "PHASES OCCUPIED ORBITALS"
     494            0 :                DO ispin = 1, nspins
     495            0 :                   DO iocc = 1, nmo_occ(ispin)
     496            0 :                      WRITE (ounit, "(F20.14)") gs_mos(ispin)%phases_occ(iocc)
     497              :                   END DO
     498              :                END DO
     499            0 :                IF (print_virtuals) THEN
     500            0 :                   WRITE (ounit, "(A)") "PHASES VIRTUAL ORBITALS"
     501            0 :                   DO ispin = 1, nspins
     502            0 :                      DO ivirt = 1, nmo_virt(ispin)
     503            0 :                         WRITE (ounit, "(F20.14)") gs_mos(ispin)%phases_virt(ivirt)
     504              :                      END DO
     505              :                   END DO
     506              :                END IF
     507              :             END IF
     508              :          END IF
     509              : 
     510            2 :          CALL cp_print_key_finished_output(ounit, logger, tddfpt_print_section, "NAMD_PRINT")
     511              : 
     512            2 :          CALL timestop(handle)
     513              :       END IF
     514              : 
     515            2 :    END SUBROUTINE tddfpt_write_newtonx_output
     516              : ! **************************************************************************************************
     517              : !> \brief ...
     518              : !> \param evects ...
     519              : !> \param ounit ...
     520              : !> \param S_evects ...
     521              : !> \param matrix_s ...
     522              : ! **************************************************************************************************
     523            0 :    SUBROUTINE tddfpt_check_orthonormality(evects, ounit, S_evects, matrix_s)
     524              : 
     525              :       TYPE(cp_fm_type), DIMENSION(:, :), INTENT(in)      :: evects
     526              :       INTEGER, INTENT(in)                                :: ounit
     527              :       TYPE(cp_fm_type), DIMENSION(:, :), INTENT(INOUT)   :: S_evects
     528              :       TYPE(dbcsr_type), INTENT(in), POINTER              :: matrix_s
     529              : 
     530              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'tddfpt_check_orthonormality'
     531              : 
     532              :       INTEGER                                            :: handle, ispin, ivect, jvect, nspins, &
     533              :                                                             nvects_total
     534              :       INTEGER, DIMENSION(maxspins)                       :: nactive
     535              :       REAL(kind=dp)                                      :: norm
     536              :       REAL(kind=dp), DIMENSION(maxspins)                 :: weights
     537              : 
     538            0 :       CALL timeset(routineN, handle)
     539              : 
     540            0 :       nspins = SIZE(evects, 1)
     541            0 :       nvects_total = SIZE(evects, 2)
     542              : 
     543              :       IF (debug_this_module) THEN
     544              :          CPASSERT(SIZE(S_evects, 1) == nspins)
     545              :          CPASSERT(SIZE(S_evects, 2) == nvects_total)
     546              :       END IF
     547              : 
     548            0 :       DO ispin = 1, nspins
     549            0 :          CALL cp_fm_get_info(matrix=evects(ispin, 1), ncol_global=nactive(ispin))
     550              :       END DO
     551              : 
     552            0 :       DO jvect = 1, nvects_total
     553              :          ! <psi1_i | psi1_j>
     554            0 :          DO ivect = 1, jvect - 1
     555            0 :             CALL cp_fm_trace(evects(:, jvect), S_evects(:, ivect), weights(1:nspins), accurate=.FALSE.)
     556            0 :             norm = SUM(weights(1:nspins))
     557              : 
     558            0 :             DO ispin = 1, nspins
     559            0 :                CALL cp_fm_scale_and_add(1.0_dp, evects(ispin, jvect), -norm, evects(ispin, ivect))
     560              :             END DO
     561              :          END DO
     562              : 
     563              :          ! <psi1_j | psi1_j>
     564            0 :          DO ispin = 1, nspins
     565              :             CALL cp_dbcsr_sm_fm_multiply(matrix_s, evects(ispin, jvect), S_evects(ispin, jvect), &
     566            0 :                                          ncol=nactive(ispin), alpha=1.0_dp, beta=0.0_dp)
     567              :          END DO
     568              : 
     569            0 :          CALL cp_fm_trace(evects(:, jvect), S_evects(:, jvect), weights(1:nspins), accurate=.FALSE.)
     570              : 
     571            0 :          norm = SUM(weights(1:nspins))
     572              :          norm = 1.0_dp/SQRT(norm)
     573              : 
     574            0 :          IF ((ounit > 0) .AND. debug_this_module) WRITE (ounit, '(A,F10.8)') "norm", norm
     575              : 
     576              :       END DO
     577              : 
     578            0 :       CALL timestop(handle)
     579              : 
     580            0 :    END SUBROUTINE tddfpt_check_orthonormality
     581              : ! **************************************************************************************************
     582              : !> \brief ...
     583              : !> \param evects ...
     584              : !> \param phase_evects ...
     585              : !> \param sub_env ...
     586              : ! **************************************************************************************************
     587            2 :    SUBROUTINE compute_phase_eigenvectors(evects, phase_evects, sub_env)
     588              : 
     589              :       ! copied from parts of tddgpt_init_ground_state_mos by S. Chulkov
     590              : 
     591              :       TYPE(cp_fm_type), INTENT(in)                       :: evects
     592              :       REAL(kind=dp), DIMENSION(:), INTENT(out)           :: phase_evects
     593              :       TYPE(tddfpt_subgroup_env_type), INTENT(in)         :: sub_env
     594              : 
     595              :       CHARACTER(len=*), PARAMETER :: routineN = 'compute_phase_eigenvectors'
     596              :       REAL(kind=dp), PARAMETER                           :: eps_dp = EPSILON(0.0_dp)
     597              : 
     598              :       INTEGER :: handle, icol_global, icol_local, irow_global, irow_local, ncol_global, &
     599              :          ncol_local, nrow_global, nrow_local, sign_int
     600              :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: minrow_neg_array, minrow_pos_array, &
     601              :                                                             sum_sign_array
     602            2 :       INTEGER, DIMENSION(:), POINTER                     :: col_indices, row_indices
     603              :       REAL(kind=dp)                                      :: element
     604              :       REAL(KIND=dp), CONTIGUOUS, DIMENSION(:, :), &
     605            2 :          POINTER                                         :: my_block
     606              : 
     607            2 :       CALL timeset(routineN, handle)
     608              : 
     609              :       ! compute and print the phase of excited-state eigenvectors:
     610              :       CALL cp_fm_get_info(evects, nrow_global=nrow_global, ncol_global=ncol_global, &
     611              :                           nrow_local=nrow_local, ncol_local=ncol_local, local_data=my_block, &
     612            2 :                           row_indices=row_indices, col_indices=col_indices) ! nrow_global either nao or nocc
     613              : 
     614           14 :       ALLOCATE (minrow_neg_array(ncol_global), minrow_pos_array(ncol_global), sum_sign_array(ncol_global))
     615           10 :       minrow_neg_array(:) = nrow_global
     616           10 :       minrow_pos_array(:) = nrow_global
     617           10 :       sum_sign_array(:) = 0
     618              : 
     619           10 :       DO icol_local = 1, ncol_local
     620            8 :          icol_global = col_indices(icol_local)
     621              : 
     622           86 :          DO irow_local = 1, nrow_local
     623           76 :             irow_global = row_indices(irow_local)
     624              : 
     625           76 :             element = my_block(irow_local, icol_local)
     626              : 
     627           76 :             sign_int = 0
     628           76 :             IF (element >= eps_dp) THEN
     629              :                sign_int = 1
     630           36 :             ELSE IF (element <= -eps_dp) THEN
     631           36 :                sign_int = -1
     632              :             END IF
     633              : 
     634           76 :             sum_sign_array(icol_global) = sum_sign_array(icol_global) + sign_int
     635              : 
     636           84 :             IF (sign_int > 0) THEN
     637           40 :                IF (minrow_pos_array(icol_global) > irow_global) &
     638            8 :                   minrow_pos_array(icol_global) = irow_global
     639           36 :             ELSE IF (sign_int < 0) THEN
     640           36 :                IF (minrow_neg_array(icol_global) > irow_global) &
     641            8 :                   minrow_neg_array(icol_global) = irow_global
     642              :             END IF
     643              : 
     644              :          END DO
     645              :       END DO
     646              : 
     647            2 :       CALL sub_env%para_env%sum(sum_sign_array)
     648            2 :       CALL sub_env%para_env%min(minrow_neg_array)
     649            2 :       CALL sub_env%para_env%min(minrow_pos_array)
     650              : 
     651           10 :       DO icol_global = 1, ncol_global
     652              : 
     653           10 :          IF (sum_sign_array(icol_global) > 0) THEN
     654              :             ! most of the expansion coefficients are positive => MO's phase = +1
     655            6 :             phase_evects(icol_global) = 1.0_dp
     656            2 :          ELSE IF (sum_sign_array(icol_global) < 0) THEN
     657              :             ! most of the expansion coefficients are negative => MO's phase = -1
     658            2 :             phase_evects(icol_global) = -1.0_dp
     659              :          ELSE
     660              :             ! equal number of positive and negative expansion coefficients
     661            0 :             IF (minrow_pos_array(icol_global) <= minrow_neg_array(icol_global)) THEN
     662              :                ! the first positive expansion coefficient has a lower index then
     663              :                ! the first negative expansion coefficient; MO's phase = +1
     664            0 :                phase_evects(icol_global) = 1.0_dp
     665              :             ELSE
     666              :                ! MO's phase = -1
     667            0 :                phase_evects(icol_global) = -1.0_dp
     668              :             END IF
     669              :          END IF
     670              : 
     671              :       END DO
     672              : 
     673            2 :       DEALLOCATE (minrow_neg_array, minrow_pos_array, sum_sign_array)
     674              : 
     675            2 :       CALL timestop(handle)
     676              : 
     677            2 :    END SUBROUTINE compute_phase_eigenvectors
     678              : 
     679              : END MODULE qs_tddfpt2_restart
        

Generated by: LCOV version 2.0-1