LCOV - code coverage report
Current view: top level - src/emd - rt_projection_mo_utils.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:71c3ab0) Lines: 96.0 % 224 215
Test Date: 2026-07-25 06:35:44 Functions: 100.0 % 6 6

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2026 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \brief Function related to MO projection in RTP calculations
      10              : !> \author Guillaume Le Breton 04.2023
      11              : ! **************************************************************************************************
      12              : MODULE rt_projection_mo_utils
      13              :    USE cp_control_types,                ONLY: dft_control_type,&
      14              :                                               proj_mo_type,&
      15              :                                               rtp_control_type
      16              :    USE cp_dbcsr_api,                    ONLY: dbcsr_p_type
      17              :    USE cp_dbcsr_operations,             ONLY: cp_dbcsr_sm_fm_multiply
      18              :    USE cp_files,                        ONLY: close_file,&
      19              :                                               open_file
      20              :    USE cp_fm_basic_linalg,              ONLY: cp_fm_scale_and_add,&
      21              :                                               cp_fm_trace
      22              :    USE cp_fm_struct,                    ONLY: cp_fm_struct_create,&
      23              :                                               cp_fm_struct_release,&
      24              :                                               cp_fm_struct_type
      25              :    USE cp_fm_types,                     ONLY: cp_fm_create,&
      26              :                                               cp_fm_release,&
      27              :                                               cp_fm_to_fm,&
      28              :                                               cp_fm_type
      29              :    USE cp_log_handling,                 ONLY: cp_get_default_logger,&
      30              :                                               cp_logger_get_default_io_unit,&
      31              :                                               cp_logger_type,&
      32              :                                               cp_to_string
      33              :    USE cp_output_handling,              ONLY: cp_p_file,&
      34              :                                               cp_print_key_finished_output,&
      35              :                                               cp_print_key_generate_filename,&
      36              :                                               cp_print_key_should_output,&
      37              :                                               cp_print_key_unit_nr
      38              :    USE input_section_types,             ONLY: section_vals_get,&
      39              :                                               section_vals_get_subs_vals,&
      40              :                                               section_vals_type,&
      41              :                                               section_vals_val_get
      42              :    USE kinds,                           ONLY: default_string_length,&
      43              :                                               dp
      44              :    USE message_passing,                 ONLY: mp_para_env_type
      45              :    USE particle_types,                  ONLY: particle_type
      46              :    USE qs_environment_types,            ONLY: get_qs_env,&
      47              :                                               qs_environment_type
      48              :    USE qs_kind_types,                   ONLY: qs_kind_type
      49              :    USE qs_mo_io,                        ONLY: read_mos_restart_low
      50              :    USE qs_mo_types,                     ONLY: deallocate_mo_set,&
      51              :                                               mo_set_type
      52              :    USE rt_propagation_types,            ONLY: get_rtp,&
      53              :                                               rt_prop_type
      54              : #include "./../base/base_uses.f90"
      55              : 
      56              :    IMPLICIT NONE
      57              :    PRIVATE
      58              : 
      59              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'rt_projection_mo_utils'
      60              : 
      61              :    PUBLIC :: init_mo_projection, compute_and_write_proj_mo
      62              : 
      63              : CONTAINS
      64              : 
      65              : ! **************************************************************************************************
      66              : !> \brief Initialize the mo projection objects for time dependent run
      67              : !> \param qs_env ...
      68              : !> \param rtp_control ...
      69              : !> \author Guillaume Le Breton (04.2023)
      70              : ! **************************************************************************************************
      71            4 :    SUBROUTINE init_mo_projection(qs_env, rtp_control)
      72              :       TYPE(qs_environment_type), POINTER                 :: qs_env
      73              :       TYPE(rtp_control_type), POINTER                    :: rtp_control
      74              : 
      75              :       INTEGER                                            :: i_rep, j_td, n_rep_val, nbr_mo_td_max, &
      76              :                                                             nrep
      77            4 :       INTEGER, DIMENSION(:), POINTER                     :: tmp_ints
      78              :       TYPE(cp_logger_type), POINTER                      :: logger
      79            4 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
      80              :       TYPE(proj_mo_type), POINTER                        :: proj_mo
      81              :       TYPE(section_vals_type), POINTER                   :: input, print_key, proj_mo_section
      82              : 
      83            4 :       NULLIFY (rtp_control%proj_mo_list, tmp_ints, proj_mo, logger, &
      84            4 :                input, proj_mo_section, print_key, mos)
      85              : 
      86            4 :       CALL get_qs_env(qs_env, input=input, mos=mos)
      87              : 
      88            4 :       proj_mo_section => section_vals_get_subs_vals(input, "DFT%REAL_TIME_PROPAGATION%PRINT%PROJECTION_MO")
      89              : 
      90              :       ! Read the input section and load the reference MOs
      91            4 :       CALL section_vals_get(proj_mo_section, n_repetition=nrep)
      92           58 :       ALLOCATE (rtp_control%proj_mo_list(nrep))
      93              : 
      94           50 :       DO i_rep = 1, nrep
      95           46 :          NULLIFY (rtp_control%proj_mo_list(i_rep)%proj_mo)
      96           46 :          ALLOCATE (rtp_control%proj_mo_list(i_rep)%proj_mo)
      97           46 :          proj_mo => rtp_control%proj_mo_list(i_rep)%proj_mo
      98              : 
      99              :          CALL section_vals_val_get(proj_mo_section, "REF_MO_FILE_NAME", i_rep_section=i_rep, &
     100           46 :                                    c_val=proj_mo%ref_mo_file_name)
     101              : 
     102              :          CALL section_vals_val_get(proj_mo_section, "REF_ADD_LUMO", i_rep_section=i_rep, &
     103           46 :                                    i_val=proj_mo%ref_nlumo)
     104              : 
     105              :          ! Relevent only in EMD
     106           46 :          IF (.NOT. rtp_control%fixed_ions) THEN
     107              :             CALL section_vals_val_get(proj_mo_section, "PROPAGATE_REF", i_rep_section=i_rep, &
     108           24 :                                       l_val=proj_mo%propagate_ref)
     109              :          END IF
     110              : 
     111              :          ! If no reference .wfn is provided, using the restart SCF file:
     112           46 :          IF (proj_mo%ref_mo_file_name == "DEFAULT") THEN
     113           38 :             CALL section_vals_val_get(input, "DFT%WFN_RESTART_FILE_NAME", n_rep_val=n_rep_val)
     114           38 :             IF (n_rep_val > 0) THEN
     115            0 :                CALL section_vals_val_get(input, "DFT%WFN_RESTART_FILE_NAME", c_val=proj_mo%ref_mo_file_name)
     116              :             ELSE
     117              :                !try to read from the filename that is generated automatically from the printkey
     118           38 :                print_key => section_vals_get_subs_vals(input, "DFT%SCF%PRINT%RESTART")
     119           38 :                logger => cp_get_default_logger()
     120              :                proj_mo%ref_mo_file_name = cp_print_key_generate_filename(logger, print_key, &
     121           38 :                                                                          extension=".wfn", my_local=.FALSE.)
     122              :             END IF
     123              :          END IF
     124              : 
     125              :          CALL section_vals_val_get(proj_mo_section, "REF_MO_INDEX", i_rep_section=i_rep, &
     126           46 :                                    i_vals=tmp_ints)
     127          194 :          ALLOCATE (proj_mo%ref_mo_index, SOURCE=tmp_ints(:))
     128              :          CALL section_vals_val_get(proj_mo_section, "REF_MO_SPIN", i_rep_section=i_rep, &
     129           46 :                                    i_val=proj_mo%ref_mo_spin)
     130              : 
     131              :          ! Read the SCF mos and store the one required
     132           46 :          CALL read_reference_mo_from_wfn(qs_env, proj_mo)
     133              : 
     134              :          ! Initialize the other parameters related to the TD mos.
     135              :          CALL section_vals_val_get(proj_mo_section, "SUM_ON_ALL_REF", i_rep_section=i_rep, &
     136           46 :                                    l_val=proj_mo%sum_on_all_ref)
     137              : 
     138              :          CALL section_vals_val_get(proj_mo_section, "TD_MO_SPIN", i_rep_section=i_rep, &
     139           46 :                                    i_val=proj_mo%td_mo_spin)
     140           46 :          IF (proj_mo%td_mo_spin > SIZE(mos)) THEN
     141              :             CALL cp_abort(__LOCATION__, &
     142              :                           "You asked to project the time dependent BETA spin while the "// &
     143              :                           "real time DFT run has only one spin defined. "// &
     144            0 :                           "Please set TD_MO_SPIN to 1 or use UKS.")
     145              :          END IF
     146              : 
     147              :          CALL section_vals_val_get(proj_mo_section, "TD_MO_INDEX", i_rep_section=i_rep, &
     148           46 :                                    i_vals=tmp_ints)
     149              : 
     150           46 :          nbr_mo_td_max = mos(proj_mo%td_mo_spin)%mo_coeff%matrix_struct%ncol_global
     151              : 
     152          194 :          ALLOCATE (proj_mo%td_mo_index, SOURCE=tmp_ints(:))
     153           46 :          IF (proj_mo%td_mo_index(1) == -1) THEN
     154           18 :             DEALLOCATE (proj_mo%td_mo_index)
     155           54 :             ALLOCATE (proj_mo%td_mo_index(nbr_mo_td_max))
     156           54 :             ALLOCATE (proj_mo%td_mo_occ(nbr_mo_td_max))
     157          126 :             DO j_td = 1, nbr_mo_td_max
     158          108 :                proj_mo%td_mo_index(j_td) = j_td
     159          126 :                proj_mo%td_mo_occ(j_td) = mos(proj_mo%td_mo_spin)%occupation_numbers(proj_mo%td_mo_index(j_td))
     160              :             END DO
     161              :          ELSE
     162           84 :             ALLOCATE (proj_mo%td_mo_occ(SIZE(proj_mo%td_mo_index)))
     163           66 :             proj_mo%td_mo_occ(:) = 0.0_dp
     164           66 :             DO j_td = 1, SIZE(proj_mo%td_mo_index)
     165           38 :                IF (proj_mo%td_mo_index(j_td) > nbr_mo_td_max) THEN
     166              :                   CALL cp_abort(__LOCATION__, &
     167              :                                 "The MO number available in the Time Dependent run "// &
     168            0 :                                 "is smaller than the MO number you have required in TD_MO_INDEX.")
     169              :                END IF
     170           66 :                proj_mo%td_mo_occ(j_td) = mos(proj_mo%td_mo_spin)%occupation_numbers(proj_mo%td_mo_index(j_td))
     171              :             END DO
     172              :          END IF
     173              : 
     174              :          CALL section_vals_val_get(proj_mo_section, "SUM_ON_ALL_TD", i_rep_section=i_rep, &
     175           50 :                                    l_val=proj_mo%sum_on_all_td)
     176              : 
     177              :       END DO
     178              : 
     179            8 :    END SUBROUTINE init_mo_projection
     180              : 
     181              : ! **************************************************************************************************
     182              : !> \brief Read the MO from .wfn file and store the required MOs for TD projections
     183              : !> \param qs_env ...
     184              : !> \param proj_mo ...
     185              : !> \author Guillaume Le Breton (04.2023)
     186              : ! **************************************************************************************************
     187           46 :    SUBROUTINE read_reference_mo_from_wfn(qs_env, proj_mo)
     188              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     189              :       TYPE(proj_mo_type), POINTER                        :: proj_mo
     190              : 
     191              :       INTEGER                                            :: i_ref, ispin, mo_index, natom, &
     192              :                                                             nbr_mo_max, nbr_ref_mo, nspins, &
     193              :                                                             real_mo_index, restart_unit
     194              :       LOGICAL                                            :: is_file
     195              :       TYPE(cp_fm_struct_type), POINTER                   :: mo_ref_fmstruct
     196              :       TYPE(cp_fm_type)                                   :: mo_coeff_temp
     197           46 :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: matrix_s
     198              :       TYPE(dft_control_type), POINTER                    :: dft_control
     199           46 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mo_qs, mo_ref_temp
     200              :       TYPE(mo_set_type), POINTER                         :: mo_set
     201              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     202           46 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     203           46 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     204              : 
     205           46 :       NULLIFY (mo_qs, mo_ref_temp, mo_set, qs_kind_set, particle_set, para_env, dft_control, &
     206           46 :                mo_ref_fmstruct, matrix_s)
     207              : 
     208              :       CALL get_qs_env(qs_env, &
     209              :                       qs_kind_set=qs_kind_set, &
     210              :                       particle_set=particle_set, &
     211              :                       dft_control=dft_control, &
     212              :                       matrix_s_kp=matrix_s, &
     213              :                       mos=mo_qs, &
     214           46 :                       para_env=para_env)
     215              : 
     216           46 :       natom = SIZE(particle_set, 1)
     217              : 
     218           46 :       nspins = SIZE(mo_qs)
     219              : 
     220          230 :       ALLOCATE (mo_ref_temp(nspins))
     221              : 
     222          138 :       DO ispin = 1, nspins
     223           92 :          mo_set => mo_qs(ispin)
     224           92 :          mo_ref_temp(ispin)%nmo = mo_set%nmo + proj_mo%ref_nlumo
     225           92 :          NULLIFY (mo_ref_fmstruct)
     226              :          CALL cp_fm_struct_create(mo_ref_fmstruct, nrow_global=mo_set%nao, &
     227           92 :                                ncol_global=mo_ref_temp(ispin)%nmo, para_env=para_env, context=mo_set%mo_coeff%matrix_struct%context)
     228           92 :          NULLIFY (mo_ref_temp(ispin)%mo_coeff)
     229           92 :          ALLOCATE (mo_ref_temp(ispin)%mo_coeff)
     230           92 :          CALL cp_fm_create(mo_ref_temp(ispin)%mo_coeff, mo_ref_fmstruct)
     231           92 :          CALL cp_fm_struct_release(mo_ref_fmstruct)
     232              : 
     233           92 :          mo_ref_temp(ispin)%nao = mo_set%nao
     234           92 :          mo_ref_temp(ispin)%homo = mo_set%homo
     235           92 :          mo_ref_temp(ispin)%nelectron = mo_set%nelectron
     236          276 :          ALLOCATE (mo_ref_temp(ispin)%eigenvalues(mo_ref_temp(ispin)%nmo))
     237          276 :          ALLOCATE (mo_ref_temp(ispin)%occupation_numbers(mo_ref_temp(ispin)%nmo))
     238          138 :          NULLIFY (mo_set)
     239              :       END DO
     240              : 
     241           46 :       IF (para_env%is_source()) THEN
     242           23 :          INQUIRE (FILE=TRIM(proj_mo%ref_mo_file_name), exist=is_file)
     243           23 :          IF (.NOT. is_file) THEN
     244              :             CALL cp_abort(__LOCATION__, &
     245            0 :                           "Reference file not found! Name of the file CP2K looked for: "//TRIM(proj_mo%ref_mo_file_name))
     246              :          END IF
     247              : 
     248              :          CALL open_file(file_name=proj_mo%ref_mo_file_name, &
     249              :                         file_action="READ", &
     250              :                         file_form="UNFORMATTED", &
     251              :                         file_status="OLD", &
     252           23 :                         unit_number=restart_unit)
     253              :       END IF
     254              : 
     255              :       CALL read_mos_restart_low(mo_ref_temp, para_env=para_env, qs_kind_set=qs_kind_set, &
     256              :                                 particle_set=particle_set, natom=natom, &
     257           46 :                                 rst_unit=restart_unit)
     258              : 
     259           46 :       IF (para_env%is_source()) CALL close_file(unit_number=restart_unit)
     260              : 
     261           46 :       IF (proj_mo%ref_mo_spin > SIZE(mo_ref_temp)) THEN
     262              :          CALL cp_abort(__LOCATION__, &
     263              :                        "Projection on spin BETA is not possible as the reference wavefunction "// &
     264            0 :                        "only has one spin channel. Use a reference .wfn calculated with UKS/LSD, or set REF_MO_SPIN to 1")
     265              :       END IF
     266              : 
     267              :       ! Store only the mos required
     268           46 :       nbr_mo_max = mo_ref_temp(proj_mo%ref_mo_spin)%mo_coeff%matrix_struct%ncol_global
     269           46 :       IF (proj_mo%ref_mo_index(1) == -1) THEN
     270           18 :          DEALLOCATE (proj_mo%ref_mo_index)
     271           54 :          ALLOCATE (proj_mo%ref_mo_index(nbr_mo_max))
     272          126 :          DO i_ref = 1, nbr_mo_max
     273          126 :             proj_mo%ref_mo_index(i_ref) = i_ref
     274              :          END DO
     275              :       ELSE
     276           66 :          DO i_ref = 1, SIZE(proj_mo%ref_mo_index)
     277           66 :             IF (proj_mo%ref_mo_index(i_ref) > nbr_mo_max) THEN
     278              :                CALL cp_abort(__LOCATION__, &
     279              :                              "The number of MOs available in the reference wavefunction "// &
     280            0 :                              "is smaller than the MO number you have requested in REF_MO_INDEX.")
     281              :             END IF
     282              :          END DO
     283              :       END IF
     284           46 :       nbr_ref_mo = SIZE(proj_mo%ref_mo_index)
     285              : 
     286           46 :       IF (nbr_ref_mo > nbr_mo_max) THEN
     287              :          CALL cp_abort(__LOCATION__, &
     288              :                        "The total number of requested MOs is larger than what is available in the reference wavefunction. "// &
     289              :                        "If you are trying to project onto virtual states, make sure they are included in the .wfn file "// &
     290            0 :                        "e.g., by the ADDED_MOS keyword in the SCF section of the input when calculating your reference.")
     291              :       END IF
     292              : 
     293              :       ! Store
     294          284 :       ALLOCATE (proj_mo%mo_ref(nbr_ref_mo))
     295              :       CALL cp_fm_struct_create(mo_ref_fmstruct, &
     296              :                                context=mo_ref_temp(proj_mo%ref_mo_spin)%mo_coeff%matrix_struct%context, &
     297              :                                nrow_global=mo_ref_temp(proj_mo%ref_mo_spin)%mo_coeff%matrix_struct%nrow_global, &
     298           46 :                                ncol_global=1)
     299              : 
     300           46 :       IF (dft_control%rtp_control%fixed_ions) THEN
     301           22 :          CALL cp_fm_create(mo_coeff_temp, mo_ref_fmstruct, 'mo_ref')
     302              :       END IF
     303              : 
     304          192 :       DO mo_index = 1, nbr_ref_mo
     305          146 :          real_mo_index = proj_mo%ref_mo_index(mo_index)
     306          146 :          IF (real_mo_index > nbr_mo_max) THEN
     307              :             CALL cp_abort(__LOCATION__, &
     308            0 :                           "One of reference mo index is larger then the total number of available mo in the .wfn file.")
     309              :          END IF
     310              : 
     311              :          ! fill with the reference mo values
     312          146 :          CALL cp_fm_create(proj_mo%mo_ref(mo_index), mo_ref_fmstruct, 'mo_ref')
     313          192 :          IF (dft_control%rtp_control%fixed_ions) THEN
     314              :             ! multiply with overlap matrix to save time later on: proj_mo%mo_ref is SxMO_ref
     315              :             CALL cp_fm_to_fm(mo_ref_temp(proj_mo%ref_mo_spin)%mo_coeff, mo_coeff_temp, &
     316              :                              ncol=1, &
     317              :                              source_start=real_mo_index, &
     318           62 :                              target_start=1)
     319           62 :             CALL cp_dbcsr_sm_fm_multiply(matrix_s(1, 1)%matrix, mo_coeff_temp, proj_mo%mo_ref(mo_index), ncol=1)
     320              :          ELSE
     321              :             ! the AO will change with times: proj_mo%mo_ref are really the MOs coeffs
     322              :             CALL cp_fm_to_fm(mo_ref_temp(proj_mo%ref_mo_spin)%mo_coeff, proj_mo%mo_ref(mo_index), &
     323              :                              ncol=1, &
     324              :                              source_start=real_mo_index, &
     325           84 :                              target_start=1)
     326              :          END IF
     327              :       END DO
     328              : 
     329              :       ! Clean temporary variables
     330          138 :       DO ispin = 1, nspins
     331          138 :          CALL deallocate_mo_set(mo_ref_temp(ispin))
     332              :       END DO
     333           46 :       DEALLOCATE (mo_ref_temp)
     334              : 
     335           46 :       CALL cp_fm_struct_release(mo_ref_fmstruct)
     336           46 :       IF (dft_control%rtp_control%fixed_ions) THEN
     337           22 :          CALL cp_fm_release(mo_coeff_temp)
     338              :       END IF
     339              : 
     340           46 :    END SUBROUTINE read_reference_mo_from_wfn
     341              : 
     342              : ! **************************************************************************************************
     343              : !> \brief Compute the projection of the current MO coefficients on reference ones
     344              : !>        and write the results.
     345              : !> \param qs_env ...
     346              : !> \param mos_new ...
     347              : !> \param proj_mo ...
     348              : !> \param n_proj ...
     349              : !> \author Guillaume Le Breton
     350              : ! **************************************************************************************************
     351           92 :    SUBROUTINE compute_and_write_proj_mo(qs_env, mos_new, proj_mo, n_proj)
     352              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     353              :       TYPE(cp_fm_type), DIMENSION(:), POINTER            :: mos_new
     354              :       TYPE(proj_mo_type)                                 :: proj_mo
     355              :       INTEGER                                            :: n_proj
     356              : 
     357              :       INTEGER                                            :: i_ref, nbr_ref_mo, nbr_ref_td
     358           92 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: phase, popu, sum_popu_ref
     359              :       TYPE(cp_fm_struct_type), POINTER                   :: mo_ref_fmstruct
     360              :       TYPE(cp_fm_type)                                   :: S_mo_ref
     361              :       TYPE(cp_logger_type), POINTER                      :: logger
     362           92 :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: matrix_s
     363              :       TYPE(dft_control_type), POINTER                    :: dft_control
     364              :       TYPE(section_vals_type), POINTER                   :: input, print_mo_section, proj_mo_section
     365              : 
     366           92 :       NULLIFY (dft_control, input, proj_mo_section, print_mo_section, logger)
     367              : 
     368          184 :       logger => cp_get_default_logger()
     369              : 
     370              :       CALL get_qs_env(qs_env, &
     371              :                       dft_control=dft_control, &
     372           92 :                       input=input)
     373              : 
     374              :       ! The general section
     375           92 :       proj_mo_section => section_vals_get_subs_vals(input, "DFT%REAL_TIME_PROPAGATION%PRINT%PROJECTION_MO")
     376              :       ! The section we are dealing in this particular subroutine call: n_proj.
     377           92 :       print_mo_section => section_vals_get_subs_vals(proj_mo_section, "PRINT", i_rep_section=n_proj)
     378              : 
     379              :       ! Propagate the reference MO if required at each time step
     380           92 :       IF (proj_mo%propagate_ref) CALL propagate_ref_mo(qs_env, proj_mo)
     381              : 
     382              :       ! Does not compute the projection if not the required time step
     383           92 :       IF (.NOT. BTEST(cp_print_key_should_output(logger%iter_info, &
     384              :                                                  print_mo_section, ""), &
     385              :                       cp_p_file)) THEN
     386              :          RETURN
     387              :       END IF
     388              : 
     389           90 :       IF (.NOT. dft_control%rtp_control%fixed_ions) THEN
     390              :          CALL get_qs_env(qs_env, &
     391           48 :                          matrix_s_kp=matrix_s)
     392              :          CALL cp_fm_struct_create(mo_ref_fmstruct, &
     393              :                                   context=proj_mo%mo_ref(1)%matrix_struct%context, &
     394              :                                   nrow_global=proj_mo%mo_ref(1)%matrix_struct%nrow_global, &
     395           48 :                                   ncol_global=1)
     396           48 :          CALL cp_fm_create(S_mo_ref, mo_ref_fmstruct, 'S_mo_ref')
     397              :       END IF
     398              : 
     399           90 :       nbr_ref_mo = SIZE(proj_mo%ref_mo_index)
     400           90 :       nbr_ref_td = SIZE(proj_mo%td_mo_index)
     401          270 :       ALLOCATE (popu(nbr_ref_td))
     402          180 :       ALLOCATE (phase(nbr_ref_td))
     403              : 
     404           90 :       IF (proj_mo%sum_on_all_ref) THEN
     405           48 :          ALLOCATE (sum_popu_ref(nbr_ref_td))
     406           24 :          sum_popu_ref(:) = 0.0_dp
     407          168 :          DO i_ref = 1, nbr_ref_mo
     408              :             ! Compute SxMO_ref for the upcoming projection later on
     409          144 :             IF (.NOT. dft_control%rtp_control%fixed_ions) THEN
     410           96 :                CALL cp_dbcsr_sm_fm_multiply(matrix_s(1, 1)%matrix, proj_mo%mo_ref(i_ref), S_mo_ref, ncol=1)
     411           96 :                CALL compute_proj_mo(popu, phase, mos_new, proj_mo, i_ref, S_mo_ref=S_mo_ref)
     412              :             ELSE
     413           48 :                CALL compute_proj_mo(popu, phase, mos_new, proj_mo, i_ref)
     414              :             END IF
     415         1032 :             sum_popu_ref(:) = sum_popu_ref(:) + popu(:)
     416              :          END DO
     417           24 :          IF (proj_mo%sum_on_all_td) THEN
     418           84 :             CALL write_proj_mo(qs_env, print_mo_section, proj_mo, popu_tot=SUM(sum_popu_ref), n_proj=n_proj)
     419              :          ELSE
     420           12 :             CALL write_proj_mo(qs_env, print_mo_section, proj_mo, popu=sum_popu_ref, n_proj=n_proj)
     421              :          END IF
     422           24 :          DEALLOCATE (sum_popu_ref)
     423              :       ELSE
     424          210 :          DO i_ref = 1, nbr_ref_mo
     425          144 :             IF (.NOT. dft_control%rtp_control%fixed_ions) THEN
     426           72 :                CALL cp_dbcsr_sm_fm_multiply(matrix_s(1, 1)%matrix, proj_mo%mo_ref(i_ref), S_mo_ref, ncol=1)
     427           72 :                CALL compute_proj_mo(popu, phase, mos_new, proj_mo, i_ref, S_mo_ref=S_mo_ref)
     428              :             ELSE
     429           72 :                CALL compute_proj_mo(popu, phase, mos_new, proj_mo, i_ref)
     430              :             END IF
     431          210 :             IF (proj_mo%sum_on_all_td) THEN
     432          504 :                CALL write_proj_mo(qs_env, print_mo_section, proj_mo, i_ref=i_ref, popu_tot=SUM(popu), n_proj=n_proj)
     433              :             ELSE
     434              : 
     435           72 :                CALL write_proj_mo(qs_env, print_mo_section, proj_mo, i_ref=i_ref, popu=popu, phase=phase, n_proj=n_proj)
     436              :             END IF
     437              :          END DO
     438              :       END IF
     439              : 
     440           90 :       IF (.NOT. dft_control%rtp_control%fixed_ions) THEN
     441           48 :          CALL cp_fm_struct_release(mo_ref_fmstruct)
     442           48 :          CALL cp_fm_release(S_mo_ref)
     443              :       END IF
     444           90 :       DEALLOCATE (popu)
     445           90 :       DEALLOCATE (phase)
     446              : 
     447          184 :    END SUBROUTINE compute_and_write_proj_mo
     448              : 
     449              : ! **************************************************************************************************
     450              : !> \brief Compute the projection of the current MO coefficients on reference ones
     451              : !> \param popu ...
     452              : !> \param phase ...
     453              : !> \param mos_new ...
     454              : !> \param proj_mo ...
     455              : !> \param i_ref ...
     456              : !> \param S_mo_ref ...
     457              : !> \author Guillaume Le Breton
     458              : ! **************************************************************************************************
     459          576 :    SUBROUTINE compute_proj_mo(popu, phase, mos_new, proj_mo, i_ref, S_mo_ref)
     460              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: popu, phase
     461              :       TYPE(cp_fm_type), DIMENSION(:), POINTER            :: mos_new
     462              :       TYPE(proj_mo_type)                                 :: proj_mo
     463              :       INTEGER                                            :: i_ref
     464              :       TYPE(cp_fm_type), OPTIONAL                         :: S_mo_ref
     465              : 
     466              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'compute_proj_mo'
     467              : 
     468              :       INTEGER                                            :: handle, j_td, nbr_ref_td, spin_td
     469              :       LOGICAL                                            :: is_emd
     470              :       REAL(KIND=dp)                                      :: imag_proj, real_proj
     471              :       TYPE(cp_fm_struct_type), POINTER                   :: mo_ref_fmstruct
     472              :       TYPE(cp_fm_type)                                   :: mo_coeff_temp
     473              : 
     474          288 :       CALL timeset(routineN, handle)
     475              : 
     476          288 :       is_emd = .FALSE.
     477          288 :       IF (PRESENT(S_mo_ref)) is_emd = .TRUE.
     478              : 
     479          288 :       nbr_ref_td = SIZE(popu)
     480          288 :       spin_td = proj_mo%td_mo_spin
     481              : 
     482              :       CALL cp_fm_struct_create(mo_ref_fmstruct, &
     483              :                                context=mos_new(1)%matrix_struct%context, &
     484              :                                nrow_global=mos_new(1)%matrix_struct%nrow_global, &
     485          288 :                                ncol_global=1)
     486          288 :       CALL cp_fm_create(mo_coeff_temp, mo_ref_fmstruct, 'mo_temp')
     487              : 
     488         1700 :       DO j_td = 1, nbr_ref_td
     489              :          ! Real part of the projection:
     490              :          real_proj = 0.0_dp
     491              :          CALL cp_fm_to_fm(mos_new(2*spin_td - 1), mo_coeff_temp, &
     492              :                           ncol=1, &
     493              :                           source_start=proj_mo%td_mo_index(j_td), &
     494         1412 :                           target_start=1)
     495         1412 :          IF (is_emd) THEN
     496              :             ! The reference MO have to be propagated in the new basis, so the projection
     497          888 :             CALL cp_fm_trace(mo_coeff_temp, S_mo_ref, real_proj)
     498              :          ELSE
     499              :             ! The reference MO is time independent. proj_mo%mo_ref(i_ref) is in fact SxMO_ref already
     500          524 :             CALL cp_fm_trace(mo_coeff_temp, proj_mo%mo_ref(i_ref), real_proj)
     501              :          END IF
     502              : 
     503              :          ! Imaginary part of the projection
     504              :          imag_proj = 0.0_dp
     505              :          CALL cp_fm_to_fm(mos_new(2*spin_td), mo_coeff_temp, &
     506              :                           ncol=1, &
     507              :                           source_start=proj_mo%td_mo_index(j_td), &
     508         1412 :                           target_start=1)
     509              : 
     510         1412 :          IF (is_emd) THEN
     511          888 :             CALL cp_fm_trace(mo_coeff_temp, S_mo_ref, imag_proj)
     512              :          ELSE
     513          524 :             CALL cp_fm_trace(mo_coeff_temp, proj_mo%mo_ref(i_ref), imag_proj)
     514              :          END IF
     515              : 
     516              :          ! Store the result
     517         1412 :          phase(j_td) = ATAN2(imag_proj, real_proj) ! in radians
     518         1700 :          popu(j_td) = proj_mo%td_mo_occ(j_td)*(real_proj**2 + imag_proj**2)
     519              :       END DO
     520              : 
     521          288 :       CALL cp_fm_struct_release(mo_ref_fmstruct)
     522          288 :       CALL cp_fm_release(mo_coeff_temp)
     523              : 
     524          288 :       CALL timestop(handle)
     525              : 
     526          288 :    END SUBROUTINE compute_proj_mo
     527              : 
     528              : ! **************************************************************************************************
     529              : !> \brief Write in one file the projection of (all) the time-dependent MO coefficients
     530              : !>        onto reference ones
     531              : !> \param qs_env ...
     532              : !> \param print_mo_section ...
     533              : !> \param proj_mo ...
     534              : !> \param i_ref ...
     535              : !> \param popu ...
     536              : !> \param phase ...
     537              : !> \param popu_tot ...
     538              : !> \param n_proj ...
     539              : !> \author Guillaume Le Breton
     540              : ! **************************************************************************************************
     541          168 :    SUBROUTINE write_proj_mo(qs_env, print_mo_section, proj_mo, i_ref, popu, phase, popu_tot, n_proj)
     542              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     543              :       TYPE(section_vals_type), POINTER                   :: print_mo_section
     544              :       TYPE(proj_mo_type)                                 :: proj_mo
     545              :       INTEGER, OPTIONAL                                  :: i_ref
     546              :       REAL(KIND=dp), DIMENSION(:), OPTIONAL              :: popu, phase
     547              :       REAL(KIND=dp), OPTIONAL                            :: popu_tot
     548              :       INTEGER, OPTIONAL                                  :: n_proj
     549              : 
     550              :       CHARACTER(LEN=default_string_length)               :: ext, filename
     551              :       INTEGER                                            :: j_td, output_unit, print_unit
     552              :       TYPE(cp_logger_type), POINTER                      :: logger
     553              : 
     554          168 :       NULLIFY (logger)
     555              : 
     556          168 :       logger => cp_get_default_logger()
     557          168 :       output_unit = cp_logger_get_default_io_unit(logger)
     558              : 
     559          168 :       IF (.NOT. (output_unit > 0)) RETURN
     560              : 
     561           84 :       IF (proj_mo%sum_on_all_ref) THEN
     562           12 :          ext = "-"//TRIM(ADJUSTL(cp_to_string(n_proj)))//"-ALL_REF.dat"
     563              :       ELSE
     564              :          ! Filename is updated wrt the reference MO number
     565              :          ext = "-"//TRIM(ADJUSTL(cp_to_string(n_proj)))// &
     566              :                "-REF-"// &
     567              :                TRIM(ADJUSTL(cp_to_string(proj_mo%ref_mo_index(i_ref))))// &
     568           72 :                ".dat"
     569              :       END IF
     570              : 
     571              :       print_unit = cp_print_key_unit_nr(logger, print_mo_section, "", &
     572           84 :                                         extension=TRIM(ext))
     573              : 
     574           84 :       IF (print_unit /= output_unit) THEN
     575           84 :          INQUIRE (UNIT=print_unit, NAME=filename)
     576              :          WRITE (UNIT=print_unit, FMT="(/,(T2,A,T40,I6))") &
     577           84 :             "Real time propagation step:", qs_env%sim_step
     578              :       ELSE
     579            0 :          WRITE (UNIT=output_unit, FMT="(/,T2,A)") "PROJECTION MO"
     580              :       END IF
     581              : 
     582           84 :       IF (proj_mo%sum_on_all_ref) THEN
     583              :          WRITE (print_unit, "(T3,A)") &
     584              :             "Projection on all the required MO number from the reference file "// &
     585           12 :             TRIM(proj_mo%ref_mo_file_name)
     586           12 :          IF (proj_mo%sum_on_all_td) THEN
     587              :             WRITE (print_unit, "(T3, A, E20.12)") &
     588            6 :                "The sum over all the TD MOs population:", popu_tot
     589              :          ELSE
     590              :             WRITE (print_unit, "(T3,A)") &
     591            6 :                "For each TD MOs required is printed: Population "
     592           42 :             DO j_td = 1, SIZE(popu)
     593           42 :                WRITE (print_unit, "(T5,1(E20.12, 1X))") popu(j_td)
     594              :             END DO
     595              :          END IF
     596              :       ELSE
     597              :          WRITE (print_unit, "(T3,A)") &
     598              :             "Projection on the MO number "// &
     599              :             TRIM(ADJUSTL(cp_to_string(proj_mo%ref_mo_index(i_ref))))// &
     600              :             " from the reference file "// &
     601           72 :             TRIM(proj_mo%ref_mo_file_name)
     602              : 
     603           72 :          IF (proj_mo%sum_on_all_td) THEN
     604              :             WRITE (print_unit, "(T3, A, E20.12)") &
     605           36 :                "The sum over all the TD MOs population:", popu_tot
     606              :          ELSE
     607              :             WRITE (print_unit, "(T3,A)") &
     608           36 :                "For each TD MOs required is printed: Population & Phase [rad] "
     609           94 :             DO j_td = 1, SIZE(popu)
     610           94 :                WRITE (print_unit, "(T5,2(E20.12, E16.8, 1X))") popu(j_td), phase(j_td)
     611              :             END DO
     612              :          END IF
     613              :       END IF
     614              : 
     615           84 :       CALL cp_print_key_finished_output(print_unit, logger, print_mo_section, "")
     616              : 
     617              :    END SUBROUTINE write_proj_mo
     618              : 
     619              : ! **************************************************************************************************
     620              : !> \brief Propagate the reference MO in case of EMD: since the nuclei moves, the MO coeff can be
     621              : !>        propagated to represent the same MO (because the AO move with the nuclei).
     622              : !>        To do so, we use the same formula as for the electrons of the system, but without the
     623              : !>        Hamiltonian:
     624              : !>        dc^j_alpha/dt = - sum_{beta, gamma} S^{-1}_{alpha, beta} B_{beta,gamma} c^j_gamma
     625              : !> \param qs_env ...
     626              : !> \param proj_mo ...
     627              : !> \author Guillaume Le Breton
     628              : ! **************************************************************************************************
     629           72 :    SUBROUTINE propagate_ref_mo(qs_env, proj_mo)
     630              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     631              :       TYPE(proj_mo_type)                                 :: proj_mo
     632              : 
     633              :       INTEGER                                            :: i_ref
     634              :       REAL(Kind=dp)                                      :: dt
     635              :       TYPE(cp_fm_struct_type), POINTER                   :: mo_ref_fmstruct
     636              :       TYPE(cp_fm_type)                                   :: d_mo
     637           24 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: SinvB
     638              :       TYPE(rt_prop_type), POINTER                        :: rtp
     639              : 
     640           24 :       CALL get_qs_env(qs_env, rtp=rtp)
     641           24 :       CALL get_rtp(rtp=rtp, SinvB=SinvB, dt=dt)
     642              : 
     643              :       CALL cp_fm_struct_create(mo_ref_fmstruct, &
     644              :                                context=proj_mo%mo_ref(1)%matrix_struct%context, &
     645              :                                nrow_global=proj_mo%mo_ref(1)%matrix_struct%nrow_global, &
     646           24 :                                ncol_global=1)
     647           24 :       CALL cp_fm_create(d_mo, mo_ref_fmstruct, 'd_mo')
     648              : 
     649          108 :       DO i_ref = 1, SIZE(proj_mo%ref_mo_index)
     650              :          ! MO(t+dt) = MO(t) - dtxS_inv.B(t).MO(t)
     651           84 :          CALL cp_dbcsr_sm_fm_multiply(SinvB(1)%matrix, proj_mo%mo_ref(i_ref), d_mo, ncol=1, alpha=-dt)
     652          108 :          CALL cp_fm_scale_and_add(1.0_dp, proj_mo%mo_ref(i_ref), 1.0_dp, d_mo)
     653              :       END DO
     654              : 
     655           24 :       CALL cp_fm_struct_release(mo_ref_fmstruct)
     656           24 :       CALL cp_fm_release(d_mo)
     657              : 
     658           24 :    END SUBROUTINE propagate_ref_mo
     659              : 
     660              : END MODULE rt_projection_mo_utils
     661              : 
        

Generated by: LCOV version 2.0-1