LCOV - code coverage report
Current view: top level - src - floquet_utils.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:561f475) Lines: 98.2 % 221 217
Test Date: 2026-06-21 06:48:54 Functions: 100.0 % 9 9

            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 Floquet stuff
      10              : !> \par History
      11              : !> \author Shridhar Shanbhag (27.01.2026)
      12              : ! **************************************************************************************************
      13              : MODULE floquet_utils
      14              :    USE cell_types,                      ONLY: cell_type,&
      15              :                                               get_cell
      16              :    USE cp_cfm_basic_linalg,             ONLY: cp_cfm_lu_invert,&
      17              :                                               cp_cfm_scale_and_add
      18              :    USE cp_cfm_types,                    ONLY: cp_cfm_create,&
      19              :                                               cp_cfm_get_submatrix,&
      20              :                                               cp_cfm_release,&
      21              :                                               cp_cfm_set_all,&
      22              :                                               cp_cfm_set_submatrix,&
      23              :                                               cp_cfm_type
      24              :    USE cp_control_types,                ONLY: dft_control_type
      25              :    USE cp_dbcsr_api,                    ONLY: dbcsr_p_type
      26              :    USE cp_files,                        ONLY: close_file,&
      27              :                                               open_file
      28              :    USE kinds,                           ONLY: default_string_length,&
      29              :                                               dp
      30              :    USE kpoint_k_r_trafo_simple,         ONLY: replicate_rs_matrices,&
      31              :                                               rs_to_kp
      32              :    USE kpoint_methods,                  ONLY: kpoint_init_cell_index
      33              :    USE kpoint_types,                    ONLY: get_kpoint_info,&
      34              :                                               kpoint_create,&
      35              :                                               kpoint_release,&
      36              :                                               kpoint_type
      37              :    USE mathconstants,                   ONLY: gaussi,&
      38              :                                               pi,&
      39              :                                               z_one,&
      40              :                                               z_zero
      41              :    USE mathlib,                         ONLY: geeig_right,&
      42              :                                               gemm_square
      43              :    USE message_passing,                 ONLY: mp_para_env_type
      44              :    USE physcon,                         ONLY: evolt
      45              :    USE post_scf_bandstructure_types,    ONLY: post_scf_bandstructure_type
      46              :    USE qs_environment_types,            ONLY: get_qs_env,&
      47              :                                               qs_environment_type
      48              :    USE qs_mo_types,                     ONLY: get_mo_set,&
      49              :                                               mo_set_type
      50              :    USE qs_moments,                      ONLY: qs_moment_kpoints_deep
      51              :    USE qs_neighbor_list_types,          ONLY: neighbor_list_set_p_type
      52              :    USE util,                            ONLY: sort
      53              : #include "./base/base_uses.f90"
      54              : 
      55              :    IMPLICIT NONE
      56              : 
      57              :    PRIVATE
      58              : 
      59              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'floquet_utils'
      60              : 
      61              :    ! Public subroutines
      62              :    PUBLIC :: build_floquet_matrix, &
      63              :              calculate_epsilon_derivative, &
      64              :              build_momentum_matrix, &
      65              :              check_floquet_conversion, &
      66              :              calculate_floquet_spectral_function, &
      67              :              write_quasi_energy, &
      68              :              write_floquet_spectral_function
      69              : 
      70              : CONTAINS
      71              : 
      72              : ! **************************************************************************************************
      73              : !> \brief ...
      74              : !> \param qs_env ...
      75              : !> \param xkp ...
      76              : !> \param e_k ...
      77              : !> \param de_dk ...
      78              : ! **************************************************************************************************
      79          204 :    SUBROUTINE calculate_epsilon_derivative(qs_env, xkp, e_k, de_dk)
      80              :       TYPE(qs_environment_type), POINTER                 :: qs_env
      81              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: xkp
      82              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :), &
      83              :          OPTIONAL                                        :: e_k
      84              :       REAL(KIND=dp), ALLOCATABLE, &
      85              :          DIMENSION(:, :, :, :), OPTIONAL                 :: de_dk
      86              : 
      87              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'calculate_epsilon_derivative'
      88              : 
      89          204 :       COMPLEX(KIND=dp), ALLOCATABLE, DIMENSION(:, :)     :: C_dH_C, C_dS_C, C_k, dH_dk_i, dS_dk_i, &
      90          204 :                                                             H_k, S_k
      91              :       INTEGER                                            :: handle, i_dir, ikp, ispin, n, n_img_all, &
      92              :                                                             n_spin, nao, nkp
      93          204 :       INTEGER, DIMENSION(:, :), POINTER                  :: index_to_cell_all
      94          204 :       INTEGER, DIMENSION(:, :, :), POINTER               :: cell_to_index_all
      95              :       LOGICAL                                            :: present_dedk, present_ek
      96          204 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: eigenvals
      97          204 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :, :)  :: H_rs, S_rs
      98              :       REAL(KIND=dp), DIMENSION(3, 3)                     :: hmat
      99              :       TYPE(cell_type), POINTER                           :: cell
     100          204 :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: matrix_ks_kp, matrix_s_kp
     101              :       TYPE(kpoint_type), POINTER                         :: kpoints_all, kpoints_scf
     102          204 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
     103              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     104              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
     105          204 :          POINTER                                         :: sab_all
     106              : 
     107          204 :       CALL timeset(routineN, handle)
     108              : 
     109          204 :       present_ek = PRESENT(e_k)  ! calculate band energies, ε_k for all kpoints xkp
     110          204 :       present_dedk = PRESENT(de_dk)  ! calculate derivative, ∇_k ε_k of band energies for all kpoints xkp
     111              : 
     112          204 :       IF (.NOT. (present_ek .OR. present_dedk)) CPABORT("Subroutine needs either e_k or de_dk")
     113              : 
     114              :       CALL get_qs_env(qs_env, &
     115              :                       matrix_ks_kp=matrix_ks_kp, &
     116              :                       matrix_s_kp=matrix_s_kp, &
     117              :                       sab_all=sab_all, &
     118              :                       cell=cell, &
     119              :                       kpoints=kpoints_scf, &
     120              :                       para_env=para_env, &
     121          204 :                       mos=mos)
     122              : 
     123          204 :       CALL get_mo_set(mo_set=mos(1), nao=nao)
     124          204 :       CALL get_cell(cell=cell, h=hmat)
     125              : 
     126          204 :       n_spin = SIZE(matrix_ks_kp, 1)
     127          204 :       nkp = SIZE(xkp, 2)
     128              : 
     129              :       ! create kpoint environment kpoints_all which contains all neighbor cells R
     130              :       ! without considering any lattice symmetry
     131          204 :       NULLIFY (kpoints_all)
     132          204 :       CALL kpoint_create(kpoints_all)
     133          204 :       CALL kpoint_init_cell_index(kpoints_all, sab_all, para_env, n_img_all)
     134          204 :       CALL get_kpoint_info(kpoints_all, cell_to_index=cell_to_index_all, index_to_cell=index_to_cell_all)
     135              : 
     136         2040 :       ALLOCATE (S_rs(1, nao, nao, n_img_all), H_rs(n_spin, nao, nao, n_img_all), source=0.0_dp)
     137              : 
     138              :       ! Convert real-space dbcsr matrices into arrays
     139          204 :       CALL replicate_rs_matrices(matrix_s_kp, kpoints_scf, S_rs, cell_to_index_all)
     140          204 :       CALL replicate_rs_matrices(matrix_ks_kp, kpoints_scf, H_rs, cell_to_index_all)
     141              : 
     142          214 :       IF (present_dedk) ALLOCATE (de_dk(n_spin, nkp, 3, nao), source=0.0_dp)
     143         1020 :       IF (present_ek) ALLOCATE (e_k(n_spin, nkp, nao), source=0.0_dp)
     144              : 
     145              : !$OMP PARALLEL DEFAULT(NONE) &
     146              : !$OMP PRIVATE(ikp, ispin, S_k, H_k, eigenvals, C_k, dS_dk_i, dH_dk_i, C_dS_C, C_dH_C) &
     147              : !$OMP SHARED(nao, n_spin, de_dk, e_k, present_ek, present_dedk, &
     148          204 : !$OMP nkp, xkp, S_rs, H_rs, index_to_cell_all, hmat)
     149              :       IF (present_dedk) ALLOCATE (dS_dk_i(nao, nao), C_dS_C(nao, nao), &
     150              :                                   dH_dk_i(nao, nao), C_dH_C(nao, nao), source=z_zero)
     151              :       ALLOCATE (C_k(nao, nao), S_k(nao, nao), H_k(nao, nao), source=z_zero)
     152              :       ALLOCATE (eigenvals(nao), source=0.0_dp)
     153              : !$OMP DO COLLAPSE(2)
     154              :       DO ispin = 1, n_spin
     155              :          DO ikp = 1, nkp
     156              : 
     157              :             ! S^R -> S(k), H^R -> H(k)
     158              :             S_k = 0
     159              :             H_k = 0
     160              :             CALL rs_to_kp(S_rs(1, :, :, :), S_k, index_to_cell_all, xkp(:, ikp))
     161              :             CALL rs_to_kp(H_rs(ispin, :, :, :), H_k, index_to_cell_all, xkp(:, ikp))
     162              : 
     163              :             ! Diagonalize H(k)C(k) = S(k)C(k)ε(k)
     164              :             CALL geeig_right(H_k, S_k, eigenvals, C_k)
     165              :             IF (present_ek) e_k(ispin, ikp, :) = eigenvals(:)
     166              : 
     167              :             IF (present_dedk) THEN
     168              :                ! Evaluate the derivatives using
     169              :                ! ∇ ε_k = C^H(k) ∇ H_k C(k) - ε_k C^H(k) ∇ S_k C(k)
     170              :                DO i_dir = 1, 3
     171              :                   CALL rs_to_kp(S_rs(1, :, :, :), dS_dk_i, index_to_cell_all, xkp(:, ikp), i_dir, hmat)
     172              :                   CALL rs_to_kp(H_rs(ispin, :, :, :), dH_dk_i, index_to_cell_all, xkp(:, ikp), i_dir, hmat)
     173              : 
     174              :                   CALL gemm_square(C_k, 'C', dS_dk_i, 'N', C_k, 'N', C_dS_C)
     175              :                   CALL gemm_square(C_k, 'C', dH_dk_i, 'N', C_k, 'N', C_dH_C)
     176              : 
     177              :                   DO n = 1, nao
     178              :                      de_dk(ispin, ikp, i_dir, n) = DBLE(C_dH_C(n, n)) - DBLE(eigenvals(n)*C_dS_C(n, n))
     179              :                   END DO
     180              :                END DO
     181              :             END IF
     182              :          END DO
     183              :       END DO
     184              : !$OMP END DO
     185              :       IF (present_dedk) DEALLOCATE (dS_dk_i, C_dS_C, dH_dk_i, C_dH_C)
     186              :       DEALLOCATE (S_k, H_k, C_k, eigenvals)
     187              : !$OMP END PARALLEL
     188          204 :       DEALLOCATE (S_rs, H_rs)
     189          204 :       CALL kpoint_release(kpoints_all)
     190              : 
     191          204 :       CALL timestop(handle)
     192              : 
     193          816 :    END SUBROUTINE calculate_epsilon_derivative
     194              : 
     195              : ! **************************************************************************************************
     196              : !> \brief ...
     197              : !> \param qs_env ...
     198              : !> \param xkp ...
     199              : !> \param momentum ...
     200              : ! **************************************************************************************************
     201            2 :    SUBROUTINE build_momentum_matrix(qs_env, xkp, momentum)
     202              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     203              :       REAL(KIND=dp), DIMENSION(3)                        :: xkp
     204              :       COMPLEX(KIND=dp), ALLOCATABLE, &
     205              :          DIMENSION(:, :, :, :)                           :: momentum
     206              : 
     207              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'build_momentum_matrix'
     208              : 
     209              :       COMPLEX(KIND=dp), ALLOCATABLE, &
     210            2 :          DIMENSION(:, :, :, :, :)                        :: dipole
     211              :       INTEGER                                            :: handle, i, i_dir, ispin, j, n_spin, nao
     212              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: xkp1
     213            2 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: e_k
     214            2 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :, :)  :: de_dk
     215              :       TYPE(dft_control_type), POINTER                    :: dft_control
     216            2 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
     217              : 
     218            2 :       CALL timeset(routineN, handle)
     219              : 
     220              :       ! We calculate momentum matrix elements p_nm = <ψ_n|-iħ∇_r|ψ_m>
     221              :       ! p_nm = <u_n|(ħk - iħ∇_r)|u_m>
     222              :       ! p_nm = i d_nm (ε_n - ε_m) + ∇_k ε_n δ_nm
     223              : 
     224            2 :       NULLIFY (dft_control)
     225            2 :       CALL get_qs_env(qs_env, dft_control=dft_control, mos=mos)
     226            2 :       CALL get_mo_set(mo_set=mos(1), nao=nao)
     227              : 
     228            2 :       ALLOCATE (xkp1(3, 1), source=0.0_dp)
     229            8 :       xkp1(:, 1) = xkp(:)
     230            2 :       CALL calculate_epsilon_derivative(qs_env, xkp1, e_k, de_dk)
     231            2 :       n_spin = dft_control%nspins
     232            2 :       CALL qs_moment_kpoints_deep(qs_env, xkp1, dipole)
     233              : 
     234              : !$OMP PARALLEL DEFAULT(NONE) &
     235              : !$OMP PRIVATE(ispin, i_dir, i, j) &
     236            2 : !$OMP SHARED(nao, n_spin, momentum, dipole, e_k, de_dk)
     237              : !$OMP DO COLLAPSE(4)
     238              :       DO ispin = 1, n_spin
     239              :          DO i_dir = 1, 3
     240              :             DO i = 1, nao
     241              :                DO j = 1, nao
     242              :                   IF (j == i) THEN
     243              :                      momentum(ispin, i_dir, i, j) = de_dk(ispin, 1, i_dir, i)
     244              :                   ELSE
     245              :                      momentum(ispin, i_dir, i, j) = gaussi*(e_k(ispin, 1, i) - e_k(ispin, 1, j))* &
     246              :                                                     dipole(ispin, 1, i_dir, i, j)
     247              :                   END IF
     248              :                END DO
     249              :             END DO
     250              :          END DO
     251              :       END DO
     252              : !$OMP END DO
     253              : !$OMP END PARALLEL
     254            2 :       DEALLOCATE (xkp1, dipole, e_k, de_dk)
     255              : 
     256            2 :       CALL timestop(handle)
     257            6 :    END SUBROUTINE build_momentum_matrix
     258              : 
     259              : ! **************************************************************************************************
     260              : !> \brief ...
     261              : !> \param qs_env ...
     262              : !> \param bs_env ...
     263              : !> \param xkp ...
     264              : !> \param ispin ...
     265              : !> \param off_diag_m ...
     266              : ! **************************************************************************************************
     267            2 :    SUBROUTINE build_off_diagonal_matrix(qs_env, bs_env, xkp, ispin, off_diag_m)
     268              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     269              :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
     270              :       REAL(KIND=dp), DIMENSION(3)                        :: xkp
     271              :       INTEGER                                            :: ispin
     272              :       COMPLEX(KIND=dp), ALLOCATABLE, DIMENSION(:, :)     :: off_diag_m
     273              : 
     274              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'build_off_diagonal_matrix'
     275              : 
     276              :       COMPLEX(KIND=dp), ALLOCATABLE, &
     277              :          DIMENSION(:, :, :, :)                           :: momentum
     278              :       COMPLEX(KIND=dp), DIMENSION(3)                     :: efactor
     279              :       INTEGER                                            :: handle, i, i_dir, j, n_spin, nao
     280              :       REAL(KIND=dp)                                      :: amplitude, omega
     281              :       REAL(KIND=dp), DIMENSION(3)                        :: e_vec, phi, polarisation
     282            2 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
     283              : 
     284            2 :       CALL timeset(routineN, handle)
     285              : 
     286              :       ! Builds the matrix that occupies the off diagonal blocks in the Floquet Matrix H_F
     287              : 
     288            8 :       polarisation(:) = bs_env%floquet_polarisation(:)
     289            8 :       IF (SQRT(SUM(polarisation**2)) < EPSILON(0.0_dp)) THEN
     290            0 :          CPABORT("Invalid (too small) polarisation vector specified for POLARISATION_PUMP")
     291              :       END IF
     292              : 
     293            2 :       amplitude = bs_env%floquet_amplitude
     294            8 :       e_vec(:) = amplitude*polarisation
     295            8 :       phi(:) = pi*bs_env%floquet_phi(:)
     296            2 :       omega = bs_env%floquet_omega
     297            2 :       n_spin = bs_env%n_spin
     298              : 
     299            2 :       CALL get_qs_env(qs_env, mos=mos)
     300            2 :       CALL get_mo_set(mo_set=mos(1), nao=nao)
     301           10 :       ALLOCATE (momentum(n_spin, 3, nao, nao), source=z_zero)
     302            2 :       CALL build_momentum_matrix(qs_env, xkp, momentum)
     303              : 
     304              :       ! E_factor(α) = (i E(α) exp(i·φ(α)))/(2ω) where α = x,y,z
     305            8 :       DO i_dir = 1, 3
     306            8 :          efactor(i_dir) = gaussi*e_vec(i_dir)*CMPLX(DCOS(phi(i_dir)), DSIN(phi(i_dir)), KIND=dp)/(2*omega)
     307              :       END DO
     308              : 
     309            8 :       DO i_dir = 1, 3
     310           56 :          DO i = 1, nao
     311          438 :             DO j = 1, nao
     312              :                off_diag_m(i, j) = off_diag_m(i, j) + &
     313          432 :                                   momentum(ispin, i_dir, i, j)*efactor(i_dir)
     314              :             END DO
     315              :          END DO
     316              :       END DO
     317            2 :       DEALLOCATE (momentum)
     318              : 
     319            2 :       CALL timestop(handle)
     320              : 
     321            4 :    END SUBROUTINE build_off_diagonal_matrix
     322              : 
     323              : ! **************************************************************************************************
     324              : !> \brief ...
     325              : !> \param qs_env ...
     326              : !> \param bs_env ...
     327              : !> \param xkp ...
     328              : !> \param ispin ...
     329              : !> \param f_index ...
     330              : !> \param diag_e ...
     331              : ! **************************************************************************************************
     332          202 :    SUBROUTINE build_diagonal_matrix(qs_env, bs_env, xkp, ispin, f_index, diag_e)
     333              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     334              :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
     335              :       REAL(KIND=dp), DIMENSION(3)                        :: xkp
     336              :       INTEGER                                            :: ispin, f_index
     337              :       COMPLEX(KIND=dp), ALLOCATABLE, DIMENSION(:, :)     :: diag_e
     338              : 
     339              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'build_diagonal_matrix'
     340              : 
     341              :       INTEGER                                            :: handle, i, n_spin, nao
     342              :       REAL(KIND=dp)                                      :: omega
     343              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: xkp1
     344          202 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: e_k
     345          202 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
     346              : 
     347          202 :       CALL timeset(routineN, handle)
     348              : 
     349              :       ! Builds the matrix that occupies the off diagonal blocks in the Floquet Matrix H_F
     350              : 
     351          202 :       omega = bs_env%floquet_omega
     352          202 :       n_spin = bs_env%n_spin
     353              : 
     354          202 :       CALL get_qs_env(qs_env, mos=mos)
     355          202 :       CALL get_mo_set(mo_set=mos(1), nao=nao)
     356          202 :       ALLOCATE (xkp1(3, 1), source=0.0_dp)
     357          808 :       xkp1(:, 1) = xkp(:)
     358          202 :       CALL calculate_epsilon_derivative(qs_env, xkp1, e_k)
     359              : 
     360         1818 :       DO i = 1, nao
     361         1818 :          diag_e(i, i) = e_k(ispin, 1, i) + f_index*omega
     362              :       END DO
     363          202 :       DEALLOCATE (xkp1, e_k)
     364          202 :       CALL timestop(handle)
     365              : 
     366          404 :    END SUBROUTINE build_diagonal_matrix
     367              : 
     368              : ! **************************************************************************************************
     369              : !> \brief ...
     370              : !> \param qs_env ...
     371              : !> \param bs_env ...
     372              : !> \param xkp ...
     373              : !> \param ispin ...
     374              : !> \param floquet_matrix ...
     375              : ! **************************************************************************************************
     376            2 :    SUBROUTINE build_floquet_matrix(qs_env, bs_env, xkp, ispin, floquet_matrix)
     377              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     378              :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
     379              :       REAL(KIND=dp), DIMENSION(3)                        :: xkp
     380              :       INTEGER                                            :: ispin
     381              :       TYPE(cp_cfm_type)                                  :: floquet_matrix
     382              : 
     383              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'build_floquet_matrix'
     384              : 
     385              :       COMPLEX(KIND=dp), ALLOCATABLE, DIMENSION(:, :)     :: conj_off_diag_m, diag_e, off_diag_m
     386              :       INTEGER                                            :: f_index, handle, i, i_f, max_f_index, &
     387              :                                                             n_fbands, n_spin, nao
     388            2 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: xkp1
     389            2 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
     390              : 
     391            2 :       CALL timeset(routineN, handle)
     392              : 
     393              :       CALL get_qs_env(qs_env, &
     394            2 :                       mos=mos)
     395            2 :       CALL get_mo_set(mo_set=mos(1), nao=nao)
     396            2 :       max_f_index = bs_env%max_floquet_index
     397            2 :       n_fbands = 1 + 2*max_f_index
     398            2 :       n_spin = bs_env%n_spin
     399              : 
     400              :       ! Creates the floquet matrix H_F by placing the diagonal and off diagonal blocks
     401              : 
     402            2 :       ALLOCATE (xkp1(3, 1), source=0.0_dp)
     403            8 :       ALLOCATE (diag_e(nao, nao), source=z_zero)
     404            6 :       ALLOCATE (off_diag_m(nao, nao), source=z_zero)
     405            6 :       ALLOCATE (conj_off_diag_m(nao, nao), source=z_zero)
     406            8 :       xkp1(:, 1) = xkp(:)
     407            2 :       CALL build_off_diagonal_matrix(qs_env, bs_env, xkp, ispin, off_diag_m)
     408          146 :       conj_off_diag_m(:, :) = CONJG(TRANSPOSE(off_diag_m(:, :)))
     409              : 
     410       654482 :       floquet_matrix%local_data(:, :) = z_zero
     411          204 :       DO i = 1, n_fbands
     412          202 :          i_f = 1 + (i - 1)*nao
     413          202 :          f_index = i - max_f_index - 1
     414          202 :          CALL build_diagonal_matrix(qs_env, bs_env, xkp, ispin, f_index, diag_e)
     415          202 :          CALL cp_cfm_set_submatrix(floquet_matrix, diag_e, i_f, i_f)
     416          204 :          IF (i > 1) THEN
     417          200 :             CALL cp_cfm_set_submatrix(floquet_matrix, off_diag_m, i_f, i_f - nao)
     418          200 :             CALL cp_cfm_set_submatrix(floquet_matrix, conj_off_diag_m, i_f - nao, i_f)
     419              :          END IF
     420              :       END DO
     421            2 :       DEALLOCATE (diag_e, off_diag_m, conj_off_diag_m, xkp1)
     422              : 
     423            2 :       CALL timestop(handle)
     424            4 :    END SUBROUTINE build_floquet_matrix
     425              : 
     426              : ! **************************************************************************************************
     427              : !> \brief ...
     428              : !> \param qs_env ...
     429              : !> \param bs_env ...
     430              : !> \param cfm_eigenvectors ...
     431              : ! **************************************************************************************************
     432            2 :    SUBROUTINE check_floquet_conversion(qs_env, bs_env, cfm_eigenvectors)
     433              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     434              :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
     435              :       TYPE(cp_cfm_type)                                  :: cfm_eigenvectors
     436              : 
     437              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'check_floquet_conversion'
     438              : 
     439              :       COMPLEX(KIND=dp), ALLOCATABLE, DIMENSION(:, :)     :: vector_block_0, vector_block_1
     440              :       INTEGER                                            :: handle, max_f_index, nao, start_row_0, &
     441              :                                                             start_row_1
     442            2 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
     443              : 
     444            2 :       CALL timeset(routineN, handle)
     445              : 
     446            2 :       CALL get_qs_env(qs_env, mos=mos)
     447            2 :       CALL get_mo_set(mo_set=mos(1), nao=nao)
     448              : 
     449            2 :       max_f_index = bs_env%max_floquet_index
     450              : 
     451            2 :       start_row_0 = 1 + nao*max_f_index
     452            2 :       start_row_1 = 1 + nao*(max_f_index + 1)
     453              : 
     454           12 :       ALLOCATE (vector_block_0(3*nao, nao), vector_block_1(3*nao, nao), source=z_zero)
     455            2 :       CALL cp_cfm_get_submatrix(cfm_eigenvectors, vector_block_0, start_row_0, start_row_0)
     456            2 :       CALL cp_cfm_get_submatrix(cfm_eigenvectors, vector_block_1, start_row_1, start_row_1)
     457            2 :       IF (bs_env%eps_floquet > 0) THEN
     458          802 :          IF (ABS(MAXVAL(ABS(vector_block_0)) - MAXVAL(ABS(vector_block_1))) > bs_env%eps_floquet) THEN
     459            0 :             CPABORT("FLOQUET DIAGONALIZATION DID NOT CONVERGE. MAX_FLOQUET_INDEX TOO SMALL")
     460              :          END IF
     461              :       END IF
     462            2 :       DEALLOCATE (vector_block_0, vector_block_1)
     463            2 :       CALL timestop(handle)
     464              : 
     465            4 :    END SUBROUTINE check_floquet_conversion
     466              : 
     467              : ! **************************************************************************************************
     468              : !> \brief ...
     469              : !> \param qs_env ...
     470              : !> \param bs_env ...
     471              : !> \param floquet_matrix ...
     472              : !> \param a_k ...
     473              : ! **************************************************************************************************
     474            2 :    SUBROUTINE calculate_floquet_spectral_function(qs_env, bs_env, floquet_matrix, a_k)
     475              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     476              :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
     477              :       TYPE(cp_cfm_type)                                  :: floquet_matrix
     478              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: a_k
     479              : 
     480              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'calculate_floquet_spectral_function'
     481              : 
     482              :       COMPLEX(KIND=dp)                                   :: diag
     483              :       COMPLEX(KIND=dp), ALLOCATABLE, DIMENSION(:, :)     :: g00
     484              :       INTEGER                                            :: handle, i, i_E, max_f_index, n_E, nao, &
     485              :                                                             start_row_g00
     486              :       REAL(KIND=dp)                                      :: broad, E_min, energy, energy_step, mu
     487              :       TYPE(cp_cfm_type)                                  :: g_r
     488            2 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
     489              : 
     490            2 :       CALL timeset(routineN, handle)
     491              : 
     492            2 :       CALL get_qs_env(qs_env, mos=mos)
     493              : 
     494            2 :       CALL get_mo_set(mo_set=mos(1), mu=mu, nao=nao)
     495              : 
     496            2 :       broad = bs_env%broadening_floquet
     497            2 :       energy_step = bs_env%energy_step_floquet
     498            2 :       E_min = mu - bs_env%energy_window_floquet
     499            2 :       max_f_index = bs_env%max_floquet_index
     500            2 :       n_E = SIZE(a_k)
     501            2 :       start_row_g00 = 1 + nao*max_f_index
     502              : 
     503            8 :       ALLOCATE (g00(nao, nao))
     504            2 :       CALL cp_cfm_create(g_r, floquet_matrix%matrix_struct, set_zero=.TRUE.)
     505              : 
     506           10 :       DO i_E = 1, n_E
     507            8 :          energy = E_min + i_E*energy_step
     508            8 :          diag = energy + gaussi*broad/2.0_dp
     509            8 :          CALL cp_cfm_set_all(g_r, z_zero, diag)
     510            8 :          CALL cp_cfm_scale_and_add(z_one, g_r, -z_one, floquet_matrix)
     511            8 :          CALL cp_cfm_lu_invert(g_r)
     512            8 :          g00(:, :) = 0.0_dp
     513            8 :          CALL cp_cfm_get_submatrix(g_r, g00, start_row_g00, start_row_g00)
     514          146 :          a_k(i_E) = -AIMAG(SUM([(g00(i, i), i=1, nao)]))/pi
     515              :       END DO
     516              : 
     517            2 :       DEALLOCATE (g00)
     518            2 :       CALL cp_cfm_release(g_r)
     519              : 
     520            2 :       CALL timestop(handle)
     521              : 
     522            4 :    END SUBROUTINE calculate_floquet_spectral_function
     523              : 
     524              : ! **************************************************************************************************
     525              : !> \brief ...
     526              : !> \param qs_env ...
     527              : !> \param bs_env ...
     528              : !> \param ispin ...
     529              : !> \param ikp_for_file ...
     530              : !> \param xkp ...
     531              : !> \param eigenvalues ...
     532              : ! **************************************************************************************************
     533            2 :    SUBROUTINE write_quasi_energy(qs_env, bs_env, ispin, ikp_for_file, xkp, eigenvalues)
     534              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     535              :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
     536              :       INTEGER                                            :: ispin, ikp_for_file
     537              :       REAL(KIND=dp), DIMENSION(3)                        :: xkp
     538              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: eigenvalues
     539              : 
     540              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'write_quasi_energy'
     541              : 
     542              :       CHARACTER(LEN=default_string_length)               :: fname
     543              :       INTEGER                                            :: handle, i, j, n, nao, nkp_start, qunit
     544            2 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: indices, work
     545              :       REAL(KIND=dp)                                      :: fbz_max, fbz_min, omega, qe
     546            2 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: quasi_energies
     547            2 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
     548              : 
     549            2 :       CALL timeset(routineN, handle)
     550              : 
     551            2 :       CALL get_qs_env(qs_env, mos=mos)
     552            2 :       CALL get_mo_set(mo_set=mos(1), nao=nao)
     553              : 
     554            2 :       nkp_start = bs_env%nkp_only_DOS
     555            2 :       omega = bs_env%floquet_omega
     556            2 :       fbz_max = omega/2.0_dp
     557            2 :       fbz_min = -omega/2.0_dp
     558              : 
     559            2 :       n = SIZE(eigenvalues)
     560           12 :       ALLOCATE (indices(nao), work(nao), quasi_energies(nao))
     561           34 :       indices(:) = [(i, i=1, nao)]
     562           18 :       DO i = 1, nao
     563        12946 :          DO j = 1, n
     564       115776 :             IF (ANY(indices == j)) CYCLE
     565        12816 :             IF (ABS(eigenvalues(j)) < ABS(eigenvalues(indices(i)))) indices(i) = j
     566              :          END DO
     567              :       END DO
     568            2 :       CALL sort(indices, nao, work)
     569              : 
     570           18 :       quasi_energies(:) = eigenvalues(indices(:))
     571              : 
     572            2 :       IF (bs_env%para_env%is_source()) THEN
     573            1 :          WRITE (fname, "(2A)") TRIM(bs_env%floquet_qe_file), ".bs"
     574            1 :          IF (ikp_for_file == 1) THEN
     575              :             CALL open_file(TRIM(fname), unit_number=qunit, file_status="REPLACE", &
     576            1 :                            file_action="WRITE")
     577              :          ELSE
     578              :             CALL open_file(TRIM(fname), unit_number=qunit, file_status="OLD", &
     579            0 :                            file_action="WRITE", file_position="APPEND")
     580              :          END IF
     581              : 
     582            1 :          WRITE (qunit, "(A)") "# Quasi-energies obtained by diagonalising the Floquet Hamiltonian"
     583            1 :          WRITE (qunit, "(A)") "# (in units of eV, folded to Floquet Brillouin zone)"
     584              :          WRITE (qunit, "(A,I0,T10,A,I0,A,T24,3(1X,F14.8))") &
     585            1 :             "#  Spin ", ispin, "  Point ", ikp_for_file, ": ", xkp(1:3)
     586            1 :          WRITE (qunit, "(A)") "#  Floquet band  Quasi-energy [eV]"
     587            9 :          DO i = 1, nao
     588            8 :             qe = quasi_energies(i)
     589            9 :             WRITE (qunit, "(I8,F21.8)") i, qe*evolt
     590              :          END DO
     591            1 :          CALL close_file(qunit)
     592              :       END IF
     593            2 :       DEALLOCATE (indices, work, quasi_energies)
     594              : 
     595            2 :       CALL timestop(handle)
     596              : 
     597            4 :    END SUBROUTINE write_quasi_energy
     598              : ! **************************************************************************************************
     599              : !> \brief ...
     600              : !> \param qs_env ...
     601              : !> \param bs_env ...
     602              : !> \param ispin ...
     603              : !> \param ikp_for_file ...
     604              : !> \param xkp ...
     605              : !> \param a_k ...
     606              : ! **************************************************************************************************
     607            4 :    SUBROUTINE write_floquet_spectral_function(qs_env, bs_env, ispin, ikp_for_file, xkp, a_k)
     608              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     609              :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
     610              :       INTEGER                                            :: ispin, ikp_for_file
     611              :       REAL(KIND=dp), DIMENSION(3)                        :: xkp
     612              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: a_k
     613              : 
     614              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'write_floquet_spectral_function'
     615              : 
     616              :       CHARACTER(LEN=default_string_length)               :: fname
     617              :       INTEGER                                            :: handle, i_E, n_E, nkp_start, wunit
     618              :       REAL(KIND=dp)                                      :: E_min, energy, energy_step, mu
     619            2 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
     620              : 
     621            2 :       CALL timeset(routineN, handle)
     622              : 
     623            2 :       CALL get_qs_env(qs_env, mos=mos)
     624              : 
     625            2 :       CALL get_mo_set(mo_set=mos(1), mu=mu)
     626              : 
     627            2 :       energy_step = bs_env%energy_step_floquet
     628            2 :       E_min = mu - bs_env%energy_window_floquet
     629            2 :       n_E = SIZE(a_k)
     630            2 :       nkp_start = bs_env%nkp_only_DOS
     631              : 
     632            2 :       IF (bs_env%para_env%is_source()) THEN
     633            1 :          WRITE (fname, "(2A)") TRIM(bs_env%floquet_dos_file), ".out"
     634            1 :          IF (ikp_for_file == 1) THEN
     635              :             CALL open_file(TRIM(fname), unit_number=wunit, file_status="REPLACE", &
     636            1 :                            file_action="WRITE")
     637              :          ELSE
     638              :             CALL open_file(TRIM(fname), unit_number=wunit, file_status="OLD", &
     639            0 :                            file_action="WRITE", file_position="APPEND")
     640              :          END IF
     641              : 
     642            1 :          WRITE (wunit, "(A)") "# Floquet Density of States: D(ω,k) = -1/π*Im[Tr_KS(G^R(ω,k))]"
     643              :          WRITE (wunit, "(A,I0,T10,A,I0,A,T24,3(1X,F14.8))") &
     644            1 :             "#  Spin ", ispin, "  Point ", ikp_for_file, ": ", xkp(1:3)
     645            1 :          WRITE (wunit, "(A)") "#Energy-E_F (eV)  A(ω,k) = DOS (1/eV)"
     646            5 :          DO i_E = 1, n_E
     647            4 :             energy = E_min + i_E*energy_step
     648            5 :             WRITE (wunit, "(2X,2G13.4)") energy*evolt, a_k(i_E)/evolt
     649              :          END DO
     650            1 :          CALL close_file(wunit)
     651              :       END IF
     652              : 
     653            2 :       CALL timestop(handle)
     654              : 
     655            2 :    END SUBROUTINE write_floquet_spectral_function
     656              : 
     657              : END MODULE floquet_utils
        

Generated by: LCOV version 2.0-1