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

Generated by: LCOV version 1.15