LCOV - code coverage report
Current view: top level - src/emd - rt_delta_pulse.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:71c3ab0) Lines: 98.4 % 321 316
Test Date: 2026-07-25 06:35:44 Functions: 100.0 % 5 5

            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 Routines to apply a delta pulse for RTP and EMD
      10              : ! **************************************************************************************************
      11              : 
      12              : MODULE rt_delta_pulse
      13              :    USE bibliography,                    ONLY: Mattiat2019,&
      14              :                                               Mattiat2022,&
      15              :                                               cite_reference
      16              :    USE cell_types,                      ONLY: cell_type
      17              :    USE commutator_rpnl,                 ONLY: build_com_mom_nl,&
      18              :                                               build_com_nl_mag
      19              :    USE cp_blacs_env,                    ONLY: cp_blacs_env_type
      20              :    USE cp_cfm_basic_linalg,             ONLY: cp_cfm_column_scale
      21              :    USE cp_cfm_diag,                     ONLY: cp_cfm_heevd
      22              :    USE cp_cfm_types,                    ONLY: cp_cfm_create,&
      23              :                                               cp_cfm_release,&
      24              :                                               cp_cfm_to_cfm,&
      25              :                                               cp_cfm_type
      26              :    USE cp_control_types,                ONLY: dft_control_type,&
      27              :                                               rtp_control_type
      28              :    USE cp_dbcsr_api,                    ONLY: &
      29              :         dbcsr_add, dbcsr_copy, dbcsr_create, dbcsr_deallocate_matrix, dbcsr_get_info, &
      30              :         dbcsr_init_p, dbcsr_p_type, dbcsr_set, dbcsr_type, dbcsr_type_antisymmetric, &
      31              :         dbcsr_type_symmetric
      32              :    USE cp_dbcsr_cp2k_link,              ONLY: cp_dbcsr_alloc_block_from_nbl
      33              :    USE cp_dbcsr_operations,             ONLY: copy_dbcsr_to_fm,&
      34              :                                               cp_dbcsr_sm_fm_multiply,&
      35              :                                               dbcsr_allocate_matrix_set,&
      36              :                                               dbcsr_deallocate_matrix_set
      37              :    USE cp_fm_basic_linalg,              ONLY: cp_fm_scale_and_add,&
      38              :                                               cp_fm_triangular_multiply,&
      39              :                                               cp_fm_uplo_to_full
      40              :    USE cp_fm_cholesky,                  ONLY: cp_fm_cholesky_decompose,&
      41              :                                               cp_fm_cholesky_invert,&
      42              :                                               cp_fm_cholesky_reduce,&
      43              :                                               cp_fm_cholesky_restore
      44              :    USE cp_fm_diag,                      ONLY: cp_fm_syevd
      45              :    USE cp_fm_struct,                    ONLY: cp_fm_struct_create,&
      46              :                                               cp_fm_struct_release,&
      47              :                                               cp_fm_struct_type
      48              :    USE cp_fm_types,                     ONLY: cp_fm_create,&
      49              :                                               cp_fm_get_info,&
      50              :                                               cp_fm_release,&
      51              :                                               cp_fm_set_all,&
      52              :                                               cp_fm_to_fm,&
      53              :                                               cp_fm_type
      54              :    USE cp_log_handling,                 ONLY: cp_get_default_logger,&
      55              :                                               cp_logger_type
      56              :    USE cp_output_handling,              ONLY: cp_print_key_unit_nr
      57              :    USE input_section_types,             ONLY: section_get_ival,&
      58              :                                               section_get_lval,&
      59              :                                               section_vals_get_subs_vals,&
      60              :                                               section_vals_type,&
      61              :                                               section_vals_val_get
      62              :    USE kinds,                           ONLY: dp
      63              :    USE mathconstants,                   ONLY: one,&
      64              :                                               twopi,&
      65              :                                               zero
      66              :    USE message_passing,                 ONLY: mp_para_env_type
      67              :    USE moments_utils,                   ONLY: get_reference_point
      68              :    USE parallel_gemm_api,               ONLY: parallel_gemm
      69              :    USE particle_types,                  ONLY: particle_type
      70              :    USE qs_dftb_matrices,                ONLY: build_dftb_overlap
      71              :    USE qs_environment_types,            ONLY: get_qs_env,&
      72              :                                               qs_environment_type
      73              :    USE qs_kind_types,                   ONLY: qs_kind_type
      74              :    USE qs_mo_types,                     ONLY: get_mo_set,&
      75              :                                               mo_set_type
      76              :    USE qs_moments,                      ONLY: build_berry_moment_matrix,&
      77              :                                               build_local_magmom_matrix,&
      78              :                                               build_local_moment_matrix
      79              :    USE qs_neighbor_list_types,          ONLY: neighbor_list_set_p_type
      80              :    USE rt_propagation_types,            ONLY: get_rtp,&
      81              :                                               rt_prop_create_mos,&
      82              :                                               rt_prop_type
      83              : #include "../base/base_uses.f90"
      84              : 
      85              :    IMPLICIT NONE
      86              : 
      87              :    PRIVATE
      88              : 
      89              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'rt_delta_pulse'
      90              : 
      91              :    PUBLIC :: apply_delta_pulse
      92              : 
      93              : CONTAINS
      94              : 
      95              : ! **************************************************************************************************
      96              : !> \brief Interface to call the delta pulse depending on the type of calculation.
      97              : !> \param qs_env ...
      98              : !> \param rtp ...
      99              : !> \param rtp_control ...
     100              : !> \author Update: Guillaume Le Breton (2023.01)
     101              : ! **************************************************************************************************
     102              : 
     103           58 :    SUBROUTINE apply_delta_pulse(qs_env, rtp, rtp_control)
     104              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     105              :       TYPE(rt_prop_type), POINTER                        :: rtp
     106              :       TYPE(rtp_control_type), POINTER                    :: rtp_control
     107              : 
     108              :       CHARACTER(LEN=3), DIMENSION(3)                     :: rlab
     109              :       INTEGER                                            :: i, output_unit
     110              :       LOGICAL                                            :: my_apply_pulse, periodic
     111              :       REAL(KIND=dp), DIMENSION(3)                        :: kvec
     112              :       TYPE(cell_type), POINTER                           :: cell
     113           58 :       TYPE(cp_fm_type), DIMENSION(:), POINTER            :: mos_new, mos_old
     114              :       TYPE(cp_logger_type), POINTER                      :: logger
     115           58 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_s
     116              :       TYPE(dft_control_type), POINTER                    :: dft_control
     117           58 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
     118              :       TYPE(section_vals_type), POINTER                   :: input, rtp_section
     119              : 
     120           58 :       NULLIFY (logger, input, rtp_section)
     121              : 
     122          116 :       logger => cp_get_default_logger()
     123              :       CALL get_qs_env(qs_env, &
     124              :                       cell=cell, &
     125              :                       input=input, &
     126              :                       dft_control=dft_control, &
     127           58 :                       matrix_s=matrix_s)
     128           58 :       rtp_section => section_vals_get_subs_vals(input, "DFT%REAL_TIME_PROPAGATION")
     129              :       output_unit = cp_print_key_unit_nr(logger, rtp_section, "PRINT%PROGRAM_RUN_INFO", &
     130           58 :                                          extension=".scfLog")
     131          232 :       rlab = [CHARACTER(LEN=3) :: "X", "Y", "Z"]
     132          178 :       periodic = ANY(cell%perd > 0) ! periodic cell
     133           58 :       my_apply_pulse = .TRUE.
     134           58 :       CALL get_qs_env(qs_env, mos=mos)
     135              : 
     136           58 :       IF (rtp%linear_scaling) THEN
     137           40 :          IF (.NOT. ASSOCIATED(mos)) THEN
     138              :             CALL cp_warn(__LOCATION__, "Delta Pulse not implemented for Linear-Scaling based ground "// &
     139              :                          "state calculation. If you want to perform a Linear-Scaling RTP from a "// &
     140              :                          "Linear-Scaling GS calculation you can do the following: (i) LSCF froms "// &
     141              :                          "scratch, (ii) MO-based SCF (for 1 SCF loop for instance) with the LSCF "// &
     142              :                          "result as a restart and (iii) linear scaling RTP + delta kick (for 1 "// &
     143            0 :                          "SCF loop for instance).")
     144              :             my_apply_pulse = .FALSE.
     145              :          ELSE
     146              :             ! create temporary mos_old and mos_new to use delta kick routine designed for MOs-based RTP
     147              :             CALL rt_prop_create_mos(rtp, mos, qs_env%mpools, dft_control, &
     148              :                                     init_mos_old=.TRUE., init_mos_new=.TRUE., &
     149           40 :                                     init_mos_next=.FALSE., init_mos_admn=.FALSE.)
     150              :          END IF
     151              :       END IF
     152              : 
     153              :       IF (my_apply_pulse) THEN
     154              :          ! The amplitude of the perturbation for all the method, modulo some prefactor:
     155              :          kvec(:) = cell%h_inv(1, :)*rtp_control%delta_pulse_direction(1) + &
     156              :                    cell%h_inv(2, :)*rtp_control%delta_pulse_direction(2) + &
     157          232 :                    cell%h_inv(3, :)*rtp_control%delta_pulse_direction(3)
     158          232 :          kvec = kvec*twopi*rtp_control%delta_pulse_scale
     159              : 
     160           58 :          CALL get_rtp(rtp=rtp, mos_old=mos_old, mos_new=mos_new)
     161           58 :          IF (rtp_control%apply_delta_pulse) THEN
     162           50 :             IF (dft_control%qs_control%dftb) THEN
     163            0 :                CALL build_dftb_overlap(qs_env, 1, matrix_s)
     164              :             END IF
     165           50 :             IF (rtp_control%periodic) THEN
     166           36 :                IF (output_unit > 0) THEN
     167              :                   WRITE (UNIT=output_unit, FMT="(/,(T3,A,T40))") &
     168              :                      "An Electric Delta Kick within periodic condition is applied before running RTP.  "// &
     169           18 :                      "Its amplitude in atomic unit is:"
     170              :                   WRITE (output_unit, "(T3,3(A,A,E16.8,1X))") &
     171           72 :                      (TRIM(rlab(i)), "=", -kvec(i), i=1, 3)
     172              :                END IF
     173          144 :                CALL apply_delta_pulse_electric_periodic(qs_env, mos_old, mos_new, -kvec)
     174              :             ELSE
     175           14 :                CPWARN_IF(periodic, "This application of the delta pulse is not compatible with PBC!")
     176           14 :                IF (output_unit > 0) THEN
     177              :                   WRITE (UNIT=output_unit, FMT="(/,(T3,A,T40))") &
     178              :                      "An Electric Delta Kick within the length gauge is applied before running RTP.  "// &
     179            7 :                      "Its amplitude in atomic unit is:"
     180              :                   WRITE (output_unit, "(T3,3(A,A,E16.8,1X))") &
     181           28 :                      (TRIM(rlab(i)), "=", -kvec(i), i=1, 3)
     182              :                END IF
     183           56 :                CALL apply_delta_pulse_electric(qs_env, mos_old, mos_new, -kvec)
     184              :             END IF
     185            8 :          ELSE IF (rtp_control%apply_delta_pulse_mag) THEN
     186            8 :             CPWARN_IF(periodic, "This application of the delta pulse is not compatible with PBC!")
     187              :             ! The prefactor (strength of the magnetic field, should be divided by 2c)
     188            8 :             IF (output_unit > 0) THEN
     189              :                WRITE (UNIT=output_unit, FMT="(/,(T3,A,T40))") &
     190              :                   "A Magnetic Delta Kick is applied before running RTP.  "// &
     191            4 :                   "Its amplitude in atomic unit is:"
     192              :                WRITE (output_unit, "(T3,3(A,A,E16.8,1X))") &
     193           16 :                   (TRIM(rlab(i)), "=", -kvec(i)/2, i=1, 3)
     194              :             END IF
     195           32 :             CALL apply_delta_pulse_mag(qs_env, mos_old, mos_new, -kvec(:)/2)
     196              :          ELSE
     197            0 :             CPABORT("Code error: this case should not happen!")
     198              :          END IF
     199              :       END IF
     200              : 
     201           58 :    END SUBROUTINE apply_delta_pulse
     202              : 
     203              : ! **************************************************************************************************
     204              : !> \brief uses perturbation theory to get the proper initial conditions
     205              : !>        The len_rep option is NOT compatible with periodic boundary conditions!
     206              : !> \param qs_env ...
     207              : !> \param mos_old ...
     208              : !> \param mos_new ...
     209              : !> \param kvec ...
     210              : !> \author Joost & Martin (2011)
     211              : ! **************************************************************************************************
     212              : 
     213          180 :    SUBROUTINE apply_delta_pulse_electric_periodic(qs_env, mos_old, mos_new, kvec)
     214              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     215              :       TYPE(cp_fm_type), DIMENSION(:), POINTER            :: mos_old, mos_new
     216              :       REAL(KIND=dp), DIMENSION(3)                        :: kvec
     217              : 
     218              :       CHARACTER(len=*), PARAMETER :: routineN = 'apply_delta_pulse_electric_periodic'
     219              : 
     220              :       INTEGER                                            :: handle, icol, idir, irow, ispin, nao, &
     221              :                                                             ncol_local, nmo, nrow_local, nvirt, &
     222              :                                                             reference
     223           36 :       INTEGER, DIMENSION(:), POINTER                     :: col_indices, row_indices
     224              :       LOGICAL                                            :: com_nl, len_rep, periodic
     225              :       REAL(KIND=dp)                                      :: eps_ppnl, factor
     226              :       REAL(KIND=dp), CONTIGUOUS, DIMENSION(:, :), &
     227           36 :          POINTER                                         :: local_data
     228              :       REAL(KIND=dp), DIMENSION(3)                        :: rcc
     229           36 :       REAL(kind=dp), DIMENSION(:), POINTER               :: eigenvalues, ref_point
     230              :       TYPE(cell_type), POINTER                           :: cell
     231              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct, fm_struct_tmp
     232              :       TYPE(cp_fm_type)                                   :: eigenvectors, mat_ks, mat_tmp, momentum, &
     233              :                                                             S_chol, virtuals
     234           36 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_ks, matrix_r, matrix_rv, matrix_s
     235              :       TYPE(dft_control_type), POINTER                    :: dft_control
     236           36 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
     237              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
     238           36 :          POINTER                                         :: sab_orb, sap_ppnl
     239           36 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     240           36 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     241              :       TYPE(rt_prop_type), POINTER                        :: rtp
     242              :       TYPE(rtp_control_type), POINTER                    :: rtp_control
     243              :       TYPE(section_vals_type), POINTER                   :: input
     244              : 
     245           36 :       CALL timeset(routineN, handle)
     246              : 
     247           36 :       NULLIFY (cell, mos, rtp, matrix_s, matrix_ks, input, dft_control, particle_set, fm_struct)
     248              :       ! we need the overlap and ks matrix for a full diagonalization
     249              :       CALL get_qs_env(qs_env, &
     250              :                       cell=cell, &
     251              :                       mos=mos, &
     252              :                       rtp=rtp, &
     253              :                       matrix_s=matrix_s, &
     254              :                       matrix_ks=matrix_ks, &
     255              :                       dft_control=dft_control, &
     256              :                       input=input, &
     257           36 :                       particle_set=particle_set)
     258              : 
     259           36 :       rtp_control => dft_control%rtp_control
     260          102 :       periodic = ANY(cell%perd > 0) ! periodic cell
     261              : 
     262              :       ! relevant input parameters
     263           36 :       com_nl = section_get_lval(section_vals=input, keyword_name="DFT%REAL_TIME_PROPAGATION%COM_NL")
     264           36 :       len_rep = section_get_lval(section_vals=input, keyword_name="DFT%REAL_TIME_PROPAGATION%LEN_REP")
     265              : 
     266              :       ! calculate non-local commutator if necessary
     267           36 :       IF (com_nl) THEN
     268           20 :          CALL cite_reference(Mattiat2019)
     269           20 :          NULLIFY (qs_kind_set, sab_orb, sap_ppnl)
     270              :          CALL get_qs_env(qs_env, &
     271              :                          sap_ppnl=sap_ppnl, &
     272              :                          sab_orb=sab_orb, &
     273           20 :                          qs_kind_set=qs_kind_set)
     274           20 :          eps_ppnl = dft_control%qs_control%eps_ppnl
     275              : 
     276           20 :          NULLIFY (matrix_rv)
     277           20 :          CALL dbcsr_allocate_matrix_set(matrix_rv, 3)
     278           80 :          DO idir = 1, 3
     279           60 :             CALL dbcsr_init_p(matrix_rv(idir)%matrix)
     280              :             CALL dbcsr_create(matrix_rv(idir)%matrix, template=matrix_s(1)%matrix, &
     281           60 :                               matrix_type=dbcsr_type_antisymmetric)
     282           60 :             CALL cp_dbcsr_alloc_block_from_nbl(matrix_rv(idir)%matrix, sab_orb)
     283           80 :             CALL dbcsr_set(matrix_rv(idir)%matrix, 0._dp)
     284              :          END DO
     285           20 :          CALL build_com_mom_nl(qs_kind_set, sab_orb, sap_ppnl, eps_ppnl, particle_set, cell, matrix_rv=matrix_rv)
     286              :       END IF
     287              : 
     288              :       ! calculate dipole moment matrix if required, NOT for periodic boundary conditions!
     289           36 :       IF (len_rep) THEN
     290           10 :          CALL cite_reference(Mattiat2022)
     291           10 :          CPWARN_IF(periodic, "This application of the delta pulse is not compatible with PBC!")
     292              :          ! get reference point
     293              :          reference = section_get_ival(section_vals=input, &
     294           10 :                                       keyword_name="DFT%PRINT%MOMENTS%REFERENCE")
     295           10 :          NULLIFY (ref_point)
     296           10 :          CALL section_vals_val_get(input, "DFT%PRINT%MOMENTS%REF_POINT", r_vals=ref_point)
     297           10 :          CALL get_reference_point(rcc, qs_env=qs_env, reference=reference, ref_point=ref_point)
     298              : 
     299           10 :          NULLIFY (sab_orb)
     300           10 :          CALL get_qs_env(qs_env, sab_orb=sab_orb)
     301              :          ! calculate dipole moment operator
     302           10 :          NULLIFY (matrix_r)
     303           10 :          CALL dbcsr_allocate_matrix_set(matrix_r, 3)
     304           40 :          DO idir = 1, 3
     305           30 :             CALL dbcsr_init_p(matrix_r(idir)%matrix)
     306           30 :             CALL dbcsr_create(matrix_r(idir)%matrix, template=matrix_s(1)%matrix, matrix_type=dbcsr_type_symmetric)
     307           30 :             CALL cp_dbcsr_alloc_block_from_nbl(matrix_r(idir)%matrix, sab_orb)
     308           40 :             CALL dbcsr_set(matrix_r(idir)%matrix, 0._dp)
     309              :          END DO
     310           10 :          CALL build_local_moment_matrix(qs_env, matrix_r, 1, rcc)
     311              :       END IF
     312              : 
     313           36 :       IF (rtp_control%velocity_gauge) THEN
     314            0 :          rtp_control%vec_pot = rtp_control%vec_pot + kvec
     315              :       END IF
     316              : 
     317              :       ! struct for fm matrices
     318           36 :       fm_struct => rtp%ao_ao_fmstruct
     319              : 
     320              :       ! create matrices and get Cholesky decomposition of S
     321           36 :       CALL cp_fm_create(mat_ks, matrix_struct=fm_struct, name="mat_ks")
     322           36 :       CALL cp_fm_create(eigenvectors, matrix_struct=fm_struct, name="eigenvectors")
     323           36 :       CALL cp_fm_create(S_chol, matrix_struct=fm_struct, name="S_chol")
     324           36 :       CALL copy_dbcsr_to_fm(matrix_s(1)%matrix, S_chol)
     325           36 :       CALL cp_fm_cholesky_decompose(S_chol)
     326              : 
     327              :       ! get number of atomic orbitals
     328           36 :       CALL dbcsr_get_info(matrix_s(1)%matrix, nfullrows_total=nao)
     329              : 
     330           88 :       DO ispin = 1, SIZE(matrix_ks)
     331              :          ! diagonalize KS matrix to get occ and virt mos
     332          156 :          ALLOCATE (eigenvalues(nao))
     333           52 :          CALL cp_fm_create(mat_tmp, matrix_struct=fm_struct, name="mat_tmp")
     334           52 :          CALL copy_dbcsr_to_fm(matrix_ks(ispin)%matrix, mat_ks)
     335           52 :          CALL cp_fm_cholesky_reduce(mat_ks, S_chol)
     336           52 :          CALL cp_fm_syevd(mat_ks, mat_tmp, eigenvalues)
     337           52 :          CALL cp_fm_cholesky_restore(mat_tmp, nao, S_chol, eigenvectors, "SOLVE")
     338              : 
     339              :          ! virtuals
     340           52 :          CALL get_mo_set(mo_set=mos(ispin), nmo=nmo)
     341           52 :          nvirt = nao - nmo
     342              :          CALL cp_fm_struct_create(fm_struct_tmp, para_env=fm_struct%para_env, context=fm_struct%context, &
     343           52 :                                   nrow_global=nao, ncol_global=nvirt)
     344           52 :          CALL cp_fm_create(virtuals, matrix_struct=fm_struct_tmp, name="virtuals")
     345           52 :          CALL cp_fm_struct_release(fm_struct_tmp)
     346           52 :          CALL cp_fm_to_fm(eigenvectors, virtuals, nvirt, nmo + 1, 1)
     347              : 
     348              :          ! occupied
     349           52 :          CALL cp_fm_to_fm(eigenvectors, mos_old(2*ispin - 1), nmo, 1, 1)
     350              : 
     351              :          CALL cp_fm_struct_create(fm_struct_tmp, para_env=fm_struct%para_env, context=fm_struct%context, &
     352           52 :                                   nrow_global=nvirt, ncol_global=nmo)
     353           52 :          CALL cp_fm_create(momentum, matrix_struct=fm_struct_tmp, name="momentum")
     354           52 :          CALL cp_fm_struct_release(fm_struct_tmp)
     355              : 
     356              :          ! the momentum operator (in a given direction)
     357           52 :          CALL cp_fm_set_all(mos_new(2*ispin - 1), 0.0_dp)
     358              : 
     359          208 :          DO idir = 1, 3
     360          156 :             factor = kvec(idir)
     361          208 :             IF (factor /= 0.0_dp) THEN
     362           56 :                IF (.NOT. len_rep) THEN
     363              :                   CALL cp_dbcsr_sm_fm_multiply(matrix_s(idir + 1)%matrix, mos_old(2*ispin - 1), &
     364           42 :                                                mos_old(2*ispin), ncol=nmo)
     365              :                ELSE
     366              :                   CALL cp_dbcsr_sm_fm_multiply(matrix_r(idir)%matrix, mos_old(2*ispin - 1), &
     367           14 :                                                mos_old(2*ispin), ncol=nmo)
     368              :                END IF
     369              : 
     370           56 :                CALL cp_fm_scale_and_add(1.0_dp, mos_new(2*ispin - 1), factor, mos_old(2*ispin))
     371           56 :                IF (com_nl) THEN
     372           28 :                   CALL cp_fm_set_all(mos_old(2*ispin), 0.0_dp)
     373              :                   CALL cp_dbcsr_sm_fm_multiply(matrix_rv(idir)%matrix, mos_old(2*ispin - 1), &
     374           28 :                                                mos_old(2*ispin), ncol=nmo)
     375           28 :                   CALL cp_fm_scale_and_add(1.0_dp, mos_new(2*ispin - 1), factor, mos_old(2*ispin))
     376              :                END IF
     377              :             END IF
     378              :          END DO
     379              : 
     380           52 :          CALL parallel_gemm('T', 'N', nvirt, nmo, nao, 1.0_dp, virtuals, mos_new(2*ispin - 1), 0.0_dp, momentum)
     381              : 
     382              :          ! the tricky bit ... rescale by the eigenvalue difference
     383           52 :          IF (.NOT. len_rep) THEN
     384              :             CALL cp_fm_get_info(momentum, nrow_local=nrow_local, ncol_local=ncol_local, &
     385           38 :                                 row_indices=row_indices, col_indices=col_indices, local_data=local_data)
     386          372 :             DO icol = 1, ncol_local
     387         6398 :                DO irow = 1, nrow_local
     388         6026 :                   factor = 1/(eigenvalues(col_indices(icol)) - eigenvalues(nmo + row_indices(irow)))
     389         6360 :                   local_data(irow, icol) = factor*local_data(irow, icol)
     390              :                END DO
     391              :             END DO
     392              :          END IF
     393           52 :          CALL cp_fm_release(mat_tmp)
     394           52 :          DEALLOCATE (eigenvalues)
     395              : 
     396              :          ! now obtain the initial condition in mos_old
     397           52 :          CALL cp_fm_to_fm(eigenvectors, mos_old(2*ispin - 1), nmo, 1, 1)
     398           52 :          CALL parallel_gemm("N", "N", nao, nmo, nvirt, 1.0_dp, virtuals, momentum, 0.0_dp, mos_old(2*ispin))
     399              : 
     400           52 :          CALL cp_fm_release(virtuals)
     401          296 :          CALL cp_fm_release(momentum)
     402              :       END DO
     403              : 
     404              :       ! release matrices
     405           36 :       CALL cp_fm_release(S_chol)
     406           36 :       CALL cp_fm_release(mat_ks)
     407           36 :       CALL cp_fm_release(eigenvectors)
     408           36 :       IF (com_nl) CALL dbcsr_deallocate_matrix_set(matrix_rv)
     409           36 :       IF (len_rep) CALL dbcsr_deallocate_matrix_set(matrix_r)
     410              : 
     411              :       ! orthonormalize afterwards
     412           36 :       CALL orthonormalize_complex_mos(qs_env, mos_old)
     413              : 
     414           36 :       CALL timestop(handle)
     415              : 
     416           36 :    END SUBROUTINE apply_delta_pulse_electric_periodic
     417              : 
     418              : ! **************************************************************************************************
     419              : !> \brief applies exp(ikr) to the wavefunction.... stored in mos_old...
     420              : !> \param qs_env ...
     421              : !> \param mos_old ...
     422              : !> \param mos_new ...
     423              : !> \param kvec ...
     424              : !> \author Joost & Martin (2011)
     425              : ! **************************************************************************************************
     426              : 
     427           42 :    SUBROUTINE apply_delta_pulse_electric(qs_env, mos_old, mos_new, kvec)
     428              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     429              :       TYPE(cp_fm_type), DIMENSION(:), POINTER            :: mos_old, mos_new
     430              :       REAL(KIND=dp), DIMENSION(3)                        :: kvec
     431              : 
     432              :       CHARACTER(len=*), PARAMETER :: routineN = 'apply_delta_pulse_electric'
     433              : 
     434              :       INTEGER                                            :: handle, i, nao, nmo
     435              :       TYPE(cell_type), POINTER                           :: cell
     436              :       TYPE(cp_fm_type)                                   :: S_inv_fm, tmp
     437           14 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_s
     438              :       TYPE(dbcsr_type), POINTER                          :: cosmat, sinmat
     439              :       TYPE(dft_control_type), POINTER                    :: dft_control
     440           14 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
     441              :       TYPE(rt_prop_type), POINTER                        :: rtp
     442              :       TYPE(rtp_control_type), POINTER                    :: rtp_control
     443              : 
     444           14 :       CALL timeset(routineN, handle)
     445           14 :       NULLIFY (cell, dft_control, matrix_s, mos, rtp, rtp_control)
     446              :       CALL get_qs_env(qs_env, &
     447              :                       cell=cell, &
     448              :                       dft_control=dft_control, &
     449              :                       matrix_s=matrix_s, &
     450              :                       mos=mos, &
     451           14 :                       rtp=rtp)
     452           14 :       rtp_control => dft_control%rtp_control
     453              : 
     454           14 :       IF (rtp_control%velocity_gauge) THEN
     455            0 :          rtp_control%vec_pot = rtp_control%vec_pot + kvec
     456              :       END IF
     457              : 
     458              :       ! calculate exponentials (= Berry moments)
     459           14 :       NULLIFY (cosmat, sinmat)
     460           14 :       ALLOCATE (cosmat, sinmat)
     461           14 :       CALL dbcsr_copy(cosmat, matrix_s(1)%matrix, 'COS MOM')
     462           14 :       CALL dbcsr_copy(sinmat, matrix_s(1)%matrix, 'SIN MOM')
     463           14 :       CALL build_berry_moment_matrix(qs_env, cosmat, sinmat, kvec)
     464              : 
     465              :       ! need inverse of overlap matrix
     466           14 :       CALL cp_fm_create(S_inv_fm, matrix_struct=rtp%ao_ao_fmstruct, name="S_inv_fm")
     467           14 :       CALL cp_fm_create(tmp, matrix_struct=rtp%ao_ao_fmstruct, name="tmp_mat")
     468           14 :       CALL copy_dbcsr_to_fm(matrix_s(1)%matrix, S_inv_fm)
     469           14 :       CALL cp_fm_cholesky_decompose(S_inv_fm)
     470           14 :       CALL cp_fm_cholesky_invert(S_inv_fm)
     471           14 :       CALL cp_fm_uplo_to_full(S_inv_fm, tmp)
     472           14 :       CALL cp_fm_release(tmp)
     473              : 
     474           38 :       DO i = 1, SIZE(mos)
     475              :          ! apply exponentials to mo coefficients
     476           24 :          CALL get_mo_set(mos(i), nao=nao, nmo=nmo)
     477           24 :          CALL cp_dbcsr_sm_fm_multiply(cosmat, mos(i)%mo_coeff, mos_new(2*i - 1), ncol=nmo)
     478           24 :          CALL cp_dbcsr_sm_fm_multiply(sinmat, mos(i)%mo_coeff, mos_new(2*i), ncol=nmo)
     479              : 
     480           24 :          CALL parallel_gemm("N", "N", nao, nmo, nao, 1.0_dp, S_inv_fm, mos_new(2*i - 1), 0.0_dp, mos_old(2*i - 1))
     481           62 :          CALL parallel_gemm("N", "N", nao, nmo, nao, 1.0_dp, S_inv_fm, mos_new(2*i), 0.0_dp, mos_old(2*i))
     482              :       END DO
     483              : 
     484           14 :       CALL cp_fm_release(S_inv_fm)
     485           14 :       CALL dbcsr_deallocate_matrix(cosmat)
     486           14 :       CALL dbcsr_deallocate_matrix(sinmat)
     487              : 
     488              :       ! orthonormalize afterwards
     489           14 :       CALL orthonormalize_complex_mos(qs_env, mos_old)
     490              : 
     491           14 :       CALL timestop(handle)
     492              : 
     493           14 :    END SUBROUTINE apply_delta_pulse_electric
     494              : 
     495              : ! **************************************************************************************************
     496              : !> \brief apply magnetic delta pulse to linear order
     497              : !> \param qs_env ...
     498              : !> \param mos_old ...
     499              : !> \param mos_new ...
     500              : !> \param kvec ...
     501              : ! **************************************************************************************************
     502           40 :    SUBROUTINE apply_delta_pulse_mag(qs_env, mos_old, mos_new, kvec)
     503              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     504              :       TYPE(cp_fm_type), DIMENSION(:), POINTER            :: mos_old, mos_new
     505              :       REAL(KIND=dp), DIMENSION(3)                        :: kvec
     506              : 
     507              :       CHARACTER(len=*), PARAMETER :: routineN = 'apply_delta_pulse_mag'
     508              : 
     509              :       INTEGER                                            :: gauge_orig, handle, idir, ispin, nao, &
     510              :                                                             nmo, nrow_global, nvirt
     511              :       REAL(KIND=dp)                                      :: eps_ppnl, factor
     512              :       REAL(KIND=dp), DIMENSION(3)                        :: rcc
     513            8 :       REAL(kind=dp), DIMENSION(:), POINTER               :: eigenvalues, ref_point
     514              :       TYPE(cell_type), POINTER                           :: cell
     515              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct_tmp
     516              :       TYPE(cp_fm_type)                                   :: eigenvectors, mat_ks, perturbation, &
     517              :                                                             S_chol, virtuals
     518            8 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_ks, matrix_mag, matrix_nl, &
     519            8 :                                                             matrix_s
     520              :       TYPE(dft_control_type), POINTER                    :: dft_control
     521            8 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
     522              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
     523            8 :          POINTER                                         :: sab_all, sab_orb, sap_ppnl
     524            8 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     525            8 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     526              :       TYPE(rt_prop_type), POINTER                        :: rtp
     527              :       TYPE(section_vals_type), POINTER                   :: input
     528              : 
     529            8 :       CALL timeset(routineN, handle)
     530              : 
     531            8 :       CALL cite_reference(Mattiat2022)
     532              : 
     533            8 :       NULLIFY (rtp, dft_control, matrix_ks, matrix_s, input, mos, cell, sab_orb, sab_all, sap_ppnl, &
     534            8 :                qs_kind_set, particle_set)
     535              : 
     536              :       CALL get_qs_env(qs_env, &
     537              :                       rtp=rtp, &
     538              :                       dft_control=dft_control, &
     539              :                       mos=mos, &
     540              :                       matrix_ks=matrix_ks, &
     541              :                       matrix_s=matrix_s, &
     542              :                       input=input, &
     543              :                       cell=cell, &
     544              :                       sab_orb=sab_orb, &
     545              :                       sab_all=sab_all, &
     546            8 :                       sap_ppnl=sap_ppnl)
     547              : 
     548              :       gauge_orig = section_get_ival(section_vals=input, &
     549            8 :                                     keyword_name="DFT%REAL_TIME_PROPAGATION%GAUGE_ORIG")
     550            8 :       NULLIFY (ref_point)
     551            8 :       CALL section_vals_val_get(input, "DFT%REAL_TIME_PROPAGATION%GAUGE_ORIG_MANUAL", r_vals=ref_point)
     552            8 :       CALL get_reference_point(rcc, qs_env=qs_env, reference=gauge_orig, ref_point=ref_point)
     553              : 
     554              :       ! Create fm matrices
     555            8 :       CALL cp_fm_create(S_chol, matrix_struct=rtp%ao_ao_fmstruct, name='Cholesky S')
     556            8 :       CALL cp_fm_create(eigenvectors, matrix_struct=rtp%ao_ao_fmstruct, name="gs evecs fm")
     557            8 :       CALL cp_fm_create(mat_ks, matrix_struct=rtp%ao_ao_fmstruct, name='KS matrix')
     558              : 
     559              :       ! get nrows_global
     560            8 :       CALL cp_fm_get_info(mat_ks, nrow_global=nrow_global)
     561              : 
     562              :       ! cholesky decomposition of overlap matrix
     563            8 :       CALL copy_dbcsr_to_fm(matrix_s(1)%matrix, S_chol)
     564            8 :       CALL cp_fm_cholesky_decompose(S_chol)
     565              : 
     566              :       ! initiate perturbation matrix
     567            8 :       NULLIFY (matrix_mag)
     568            8 :       CALL dbcsr_allocate_matrix_set(matrix_mag, 3)
     569           32 :       DO idir = 1, 3
     570           24 :          CALL dbcsr_init_p(matrix_mag(idir)%matrix)
     571              :          CALL dbcsr_create(matrix_mag(idir)%matrix, template=matrix_s(1)%matrix, &
     572           24 :                            matrix_type=dbcsr_type_antisymmetric)
     573           24 :          CALL cp_dbcsr_alloc_block_from_nbl(matrix_mag(idir)%matrix, sab_orb)
     574           32 :          CALL dbcsr_set(matrix_mag(idir)%matrix, 0._dp)
     575              :       END DO
     576              :       ! construct magnetic dipole moment matrix
     577            8 :       CALL build_local_magmom_matrix(qs_env, matrix_mag, 1, ref_point=rcc)
     578              : 
     579              :       ! work matrix for non-local potential part if necessary
     580            8 :       NULLIFY (matrix_nl)
     581            8 :       IF (ASSOCIATED(sap_ppnl)) THEN
     582            8 :          CALL dbcsr_allocate_matrix_set(matrix_nl, 3)
     583           32 :          DO idir = 1, 3
     584           24 :             CALL dbcsr_init_p(matrix_nl(idir)%matrix)
     585              :             CALL dbcsr_create(matrix_nl(idir)%matrix, template=matrix_s(1)%matrix, &
     586           24 :                               matrix_type=dbcsr_type_antisymmetric)
     587           24 :             CALL cp_dbcsr_alloc_block_from_nbl(matrix_nl(idir)%matrix, sab_orb)
     588           32 :             CALL dbcsr_set(matrix_nl(idir)%matrix, 0._dp)
     589              :          END DO
     590              :          ! construct non-local contribution
     591              :          CALL get_qs_env(qs_env, &
     592              :                          qs_kind_set=qs_kind_set, &
     593            8 :                          particle_set=particle_set)
     594            8 :          eps_ppnl = dft_control%qs_control%eps_ppnl
     595              : 
     596            8 :          CALL build_com_nl_mag(qs_kind_set, sab_orb, sap_ppnl, eps_ppnl, particle_set, matrix_nl, rcc, cell)
     597              : 
     598           32 :          DO idir = 1, 3
     599           32 :             CALL dbcsr_add(matrix_mag(idir)%matrix, matrix_nl(idir)%matrix, -one, one)
     600              :          END DO
     601              : 
     602            8 :          CALL dbcsr_deallocate_matrix_set(matrix_nl)
     603              :       END IF
     604              : 
     605           20 :       DO ispin = 1, dft_control%nspins
     606              :          ! allocate eigenvalues
     607              :          NULLIFY (eigenvalues)
     608           36 :          ALLOCATE (eigenvalues(nrow_global))
     609              :          ! diagonalize KS matrix in AO basis using Cholesky decomp. of S
     610           12 :          CALL copy_dbcsr_to_fm(matrix_ks(ispin)%matrix, mat_ks)
     611           12 :          CALL cp_fm_cholesky_reduce(mat_ks, S_chol)
     612           12 :          CALL cp_fm_syevd(mat_ks, eigenvectors, eigenvalues)
     613           12 :          CALL cp_fm_triangular_multiply(S_chol, eigenvectors, invert_tr=.TRUE.)
     614              : 
     615              :          ! virtuals
     616           12 :          CALL get_mo_set(mo_set=mos(ispin), nao=nao, nmo=nmo)
     617           12 :          nvirt = nao - nmo
     618              :          CALL cp_fm_struct_create(fm_struct_tmp, para_env=rtp%ao_ao_fmstruct%para_env, context=rtp%ao_ao_fmstruct%context, &
     619           12 :                                   nrow_global=nrow_global, ncol_global=nvirt)
     620           12 :          CALL cp_fm_create(virtuals, matrix_struct=fm_struct_tmp, name="virtuals")
     621           12 :          CALL cp_fm_struct_release(fm_struct_tmp)
     622           12 :          CALL cp_fm_to_fm(eigenvectors, virtuals, nvirt, nmo + 1, 1)
     623              : 
     624              :          ! occupied
     625           12 :          CALL cp_fm_to_fm(eigenvectors, mos_old(2*ispin - 1), nmo, 1, 1)
     626              : 
     627              :          CALL cp_fm_struct_create(fm_struct_tmp, para_env=rtp%ao_ao_fmstruct%para_env, context=rtp%ao_ao_fmstruct%context, &
     628           12 :                                   nrow_global=nvirt, ncol_global=nmo)
     629           12 :          CALL cp_fm_create(perturbation, matrix_struct=fm_struct_tmp, name="perturbation")
     630           12 :          CALL cp_fm_struct_release(fm_struct_tmp)
     631              : 
     632              :          ! apply perturbation
     633           12 :          CALL cp_fm_set_all(mos_new(2*ispin - 1), 0.0_dp)
     634              : 
     635           48 :          DO idir = 1, 3
     636           36 :             factor = kvec(idir)
     637           48 :             IF (factor /= 0.0_dp) THEN
     638              :                CALL cp_dbcsr_sm_fm_multiply(matrix_mag(idir)%matrix, mos_old(2*ispin - 1), &
     639           12 :                                             mos_old(2*ispin), ncol=nmo)
     640           12 :                CALL cp_fm_scale_and_add(1.0_dp, mos_new(2*ispin - 1), factor, mos_old(2*ispin))
     641              :             END IF
     642              :          END DO
     643              : 
     644           12 :          CALL parallel_gemm('T', 'N', nvirt, nmo, nao, 1.0_dp, virtuals, mos_new(2*ispin - 1), 0.0_dp, perturbation)
     645              : 
     646           12 :          DEALLOCATE (eigenvalues)
     647              : 
     648              :          ! now obtain the initial condition in mos_old
     649           12 :          CALL cp_fm_to_fm(eigenvectors, mos_old(2*ispin - 1), nmo, 1, 1)
     650           12 :          CALL parallel_gemm("N", "N", nao, nmo, nvirt, 1.0_dp, virtuals, perturbation, 0.0_dp, mos_old(2*ispin))
     651              : 
     652           12 :          CALL cp_fm_release(virtuals)
     653           56 :          CALL cp_fm_release(perturbation)
     654              :       END DO
     655              : 
     656              :       ! deallocations
     657            8 :       CALL cp_fm_release(S_chol)
     658            8 :       CALL cp_fm_release(mat_ks)
     659            8 :       CALL cp_fm_release(eigenvectors)
     660            8 :       CALL dbcsr_deallocate_matrix_set(matrix_mag)
     661              : 
     662              :       ! orthonormalize afterwards
     663            8 :       CALL orthonormalize_complex_mos(qs_env, mos_old)
     664              : 
     665            8 :       CALL timestop(handle)
     666              : 
     667            8 :    END SUBROUTINE apply_delta_pulse_mag
     668              : 
     669              : ! **************************************************************************************************
     670              : !> \brief orthonormalize complex mos, e. g. after non-unitary transformations using Löwdin's algorithm
     671              : !> \param qs_env ...
     672              : !> \param coeffs ...
     673              : ! **************************************************************************************************
     674           58 :    SUBROUTINE orthonormalize_complex_mos(qs_env, coeffs)
     675              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     676              :       TYPE(cp_fm_type), DIMENSION(:), INTENT(INOUT), &
     677              :          POINTER                                         :: coeffs
     678              : 
     679           58 :       COMPLEX(KIND=dp), ALLOCATABLE, DIMENSION(:)        :: eigenvalues_sqrt
     680              :       INTEGER                                            :: im, ispin, j, nao, nmo, nspins, re
     681           58 :       REAL(kind=dp), ALLOCATABLE, DIMENSION(:)           :: eigenvalues
     682              :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env
     683              :       TYPE(cp_cfm_type)                                  :: oo_c, oo_v, oo_vt
     684              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct_tmp
     685              :       TYPE(cp_fm_type)                                   :: oo_1, oo_2, S_fm, tmp
     686          174 :       TYPE(cp_fm_type), DIMENSION(2)                     :: coeffs_tmp
     687           58 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_s
     688              :       TYPE(dft_control_type), POINTER                    :: dft_control
     689           58 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
     690              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     691              : 
     692           58 :       NULLIFY (para_env, blacs_env, dft_control, matrix_s, mos)
     693              :       CALL get_qs_env(qs_env, &
     694              :                       blacs_env=blacs_env, &
     695              :                       dft_control=dft_control, &
     696              :                       matrix_s=matrix_s, &
     697              :                       mos=mos, &
     698           58 :                       para_env=para_env)
     699           58 :       nspins = dft_control%nspins
     700           58 :       CALL cp_fm_get_info(coeffs(1), nrow_global=nao)
     701              : 
     702              :       ! get overlap matrix
     703              :       CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nao, ncol_global=nao, &
     704           58 :                                context=blacs_env, para_env=para_env)
     705           58 :       CALL cp_fm_create(S_fm, matrix_struct=fm_struct_tmp, name="overlap fm")
     706           58 :       CALL cp_fm_struct_release(fm_struct_tmp)
     707              :       ! copy overlap matrix
     708           58 :       CALL copy_dbcsr_to_fm(matrix_s(1)%matrix, S_fm)
     709              : 
     710          146 :       DO ispin = 1, nspins
     711           88 :          CALL get_mo_set(mos(ispin), nmo=nmo)
     712              :          CALL cp_fm_struct_create(fm_struct_tmp, para_env=para_env, context=blacs_env, &
     713           88 :                                   nrow_global=nmo, ncol_global=nmo)
     714           88 :          CALL cp_fm_create(oo_1, matrix_struct=fm_struct_tmp, name="oo_1")
     715           88 :          CALL cp_fm_create(oo_2, matrix_struct=fm_struct_tmp, name="oo_2")
     716           88 :          CALL cp_fm_struct_release(fm_struct_tmp)
     717              : 
     718           88 :          CALL cp_fm_create(tmp, matrix_struct=coeffs(2*ispin - 1)%matrix_struct, name="tmp_mat")
     719              :          ! get the complex overlap matrix in MO basis
     720              :          ! x^T S x + y^T S y + i (-y^TS x+x^T S y)
     721           88 :          CALL parallel_gemm("N", "N", nao, nmo, nao, 1.0_dp, S_fm, coeffs(2*ispin - 1), 0.0_dp, tmp)
     722           88 :          CALL parallel_gemm("T", "N", nmo, nmo, nao, 1.0_dp, coeffs(2*ispin - 1), tmp, 0.0_dp, oo_1)
     723           88 :          CALL parallel_gemm("T", "N", nmo, nmo, nao, -1.0_dp, coeffs(2*ispin), tmp, 0.0_dp, oo_2)
     724              : 
     725           88 :          CALL parallel_gemm("N", "N", nao, nmo, nao, 1.0_dp, S_fm, coeffs(2*ispin), 0.0_dp, tmp)
     726           88 :          CALL parallel_gemm("T", "N", nmo, nmo, nao, 1.0_dp, coeffs(2*ispin), tmp, 1.0_dp, oo_1)
     727           88 :          CALL parallel_gemm("T", "N", nmo, nmo, nao, 1.0_dp, coeffs(2*ispin - 1), tmp, 1.0_dp, oo_2)
     728           88 :          CALL cp_fm_release(tmp)
     729              : 
     730              :          ! complex Löwdin
     731           88 :          CALL cp_cfm_create(oo_c, oo_1%matrix_struct)
     732           88 :          CALL cp_cfm_create(oo_v, oo_1%matrix_struct)
     733           88 :          CALL cp_cfm_create(oo_vt, oo_1%matrix_struct)
     734         4455 :          oo_c%local_data = CMPLX(oo_1%local_data, oo_2%local_data, KIND=dp)
     735              : 
     736          264 :          ALLOCATE (eigenvalues(nmo))
     737          264 :          ALLOCATE (eigenvalues_sqrt(nmo))
     738           88 :          CALL cp_cfm_heevd(oo_c, oo_v, eigenvalues)
     739          622 :          eigenvalues_sqrt(:) = CMPLX(one/SQRT(eigenvalues(:)), zero, dp)
     740           88 :          CALL cp_cfm_to_cfm(oo_v, oo_vt)
     741           88 :          CALL cp_cfm_column_scale(oo_v, eigenvalues_sqrt)
     742           88 :          DEALLOCATE (eigenvalues)
     743           88 :          DEALLOCATE (eigenvalues_sqrt)
     744              :          CALL parallel_gemm('N', 'C', nmo, nmo, nmo, (1.0_dp, 0.0_dp), &
     745           88 :                             oo_v, oo_vt, (0.0_dp, 0.0_dp), oo_c)
     746         4455 :          oo_1%local_data = REAL(oo_c%local_data, KIND=dp)
     747         4455 :          oo_2%local_data = AIMAG(oo_c%local_data)
     748           88 :          CALL cp_cfm_release(oo_c)
     749           88 :          CALL cp_cfm_release(oo_v)
     750           88 :          CALL cp_cfm_release(oo_vt)
     751              : 
     752              :          ! transform coefficients accordingly
     753          264 :          DO j = 1, 2
     754          264 :             CALL cp_fm_create(coeffs_tmp(j), matrix_struct=coeffs(2*(ispin - 1) + j)%matrix_struct)
     755              :          END DO
     756              : 
     757              :          ! indices for coeffs_tmp
     758           88 :          re = 1
     759           88 :          im = 2
     760           88 :          CALL parallel_gemm("N", "N", nao, nmo, nmo, one, coeffs(2*ispin - 1), oo_1, zero, coeffs_tmp(re))
     761           88 :          CALL parallel_gemm("N", "N", nao, nmo, nmo, one, coeffs(2*ispin - 1), oo_2, zero, coeffs_tmp(im))
     762              : 
     763           88 :          CALL parallel_gemm("N", "N", nao, nmo, nmo, -one, coeffs(2*ispin), oo_2, zero, coeffs(2*ispin - 1))
     764           88 :          CALL cp_fm_scale_and_add(one, coeffs(2*ispin - 1), one, coeffs_tmp(re))
     765              : 
     766           88 :          CALL parallel_gemm("N", "N", nao, nmo, nmo, one, coeffs(2*ispin), oo_1, one, coeffs_tmp(im))
     767           88 :          CALL cp_fm_to_fm(coeffs_tmp(im), coeffs(2*ispin))
     768              : 
     769          264 :          DO j = 1, 2
     770          264 :             CALL cp_fm_release(coeffs_tmp(j))
     771              :          END DO
     772           88 :          CALL cp_fm_release(oo_1)
     773          498 :          CALL cp_fm_release(oo_2)
     774              :       END DO
     775           58 :       CALL cp_fm_release(S_fm)
     776              : 
     777          116 :    END SUBROUTINE orthonormalize_complex_mos
     778              : 
     779              : END MODULE rt_delta_pulse
        

Generated by: LCOV version 2.0-1