LCOV - code coverage report
Current view: top level - src - negf_green_methods.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:20da4d9) Lines: 107 108 99.1 %
Date: 2024-05-07 06:35:50 Functions: 6 7 85.7 %

          Line data    Source code
       1             : !--------------------------------------------------------------------------------------------------!
       2             : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3             : !   Copyright 2000-2024 CP2K developers group <https://cp2k.org>                                   !
       4             : !                                                                                                  !
       5             : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6             : !--------------------------------------------------------------------------------------------------!
       7             : 
       8             : ! **************************************************************************************************
       9             : !> \brief Subroutines to compute Green functions
      10             : ! **************************************************************************************************
      11             : MODULE negf_green_methods
      12             :    USE cp_cfm_basic_linalg,             ONLY: cp_cfm_gemm,&
      13             :                                               cp_cfm_lu_invert,&
      14             :                                               cp_cfm_norm,&
      15             :                                               cp_cfm_scale,&
      16             :                                               cp_cfm_scale_and_add,&
      17             :                                               cp_cfm_scale_and_add_fm,&
      18             :                                               cp_cfm_transpose
      19             :    USE cp_cfm_types,                    ONLY: cp_cfm_create,&
      20             :                                               cp_cfm_get_info,&
      21             :                                               cp_cfm_release,&
      22             :                                               cp_cfm_to_cfm,&
      23             :                                               cp_cfm_type,&
      24             :                                               cp_fm_to_cfm
      25             :    USE cp_fm_struct,                    ONLY: cp_fm_struct_get,&
      26             :                                               cp_fm_struct_type
      27             :    USE cp_fm_types,                     ONLY: cp_fm_get_info,&
      28             :                                               cp_fm_type
      29             :    USE kinds,                           ONLY: dp
      30             :    USE mathconstants,                   ONLY: gaussi,&
      31             :                                               z_mone,&
      32             :                                               z_one,&
      33             :                                               z_zero
      34             :    USE parallel_gemm_api,               ONLY: parallel_gemm
      35             : #include "./base/base_uses.f90"
      36             : 
      37             :    IMPLICIT NONE
      38             :    PRIVATE
      39             : 
      40             :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'negf_green_methods'
      41             :    LOGICAL, PARAMETER, PRIVATE          :: debug_this_module = .TRUE.
      42             : 
      43             :    PUBLIC :: sancho_work_matrices_type, sancho_work_matrices_create, sancho_work_matrices_release
      44             :    PUBLIC :: do_sancho, negf_contact_self_energy, negf_contact_broadening_matrix, negf_retarded_green_function
      45             : 
      46             :    TYPE sancho_work_matrices_type
      47             :       ! A_{n+1} = A_n + D_n + E_n
      48             :       TYPE(cp_cfm_type), POINTER                         :: a
      49             :       ! A0_{n+1} = A0_n + D_n
      50             :       TYPE(cp_cfm_type), POINTER                         :: a0
      51             :       ! A_inv = A^-1
      52             :       TYPE(cp_cfm_type), POINTER                         :: a_inv
      53             :       ! B_{n+1} = - B_n A_n^-1 B_n \equiv B_n A_n^-1 B_n
      54             :       TYPE(cp_cfm_type), POINTER                         :: b
      55             :       ! C_{n+1} = - C_n A_n^-1 C_n \equiv C_n A_n^-1 C_n
      56             :       TYPE(cp_cfm_type), POINTER                         :: c
      57             :       ! D_n = - B_n A_n^-1 C_n
      58             :       TYPE(cp_cfm_type), POINTER                         :: d
      59             :       ! E_n = - C_n A_n^-1 B_n
      60             :       TYPE(cp_cfm_type), POINTER                         :: e
      61             :       ! a scratch area for matrix multiplication
      62             :       TYPE(cp_cfm_type), POINTER                         :: scratch
      63             :    END TYPE sancho_work_matrices_type
      64             : 
      65             : CONTAINS
      66             : ! **************************************************************************************************
      67             : !> \brief Create work matrices required for the Lopez-Sancho algorithm.
      68             : !> \param work      work matrices to create (allocated and initialised on exit)
      69             : !> \param fm_struct dense matrix structure
      70             : !> \author Sergey Chulkov
      71             : ! **************************************************************************************************
      72        2448 :    SUBROUTINE sancho_work_matrices_create(work, fm_struct)
      73             :       TYPE(sancho_work_matrices_type), INTENT(inout)     :: work
      74             :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct
      75             : 
      76             :       CHARACTER(len=*), PARAMETER :: routineN = 'sancho_work_matrices_create'
      77             : 
      78             :       INTEGER                                            :: handle, ncols, nrows
      79             : 
      80        1224 :       CALL timeset(routineN, handle)
      81        1224 :       CPASSERT(ASSOCIATED(fm_struct))
      82             : 
      83        1224 :       CALL cp_fm_struct_get(fm_struct, nrow_global=nrows, ncol_global=ncols)
      84        1224 :       CPASSERT(nrows == ncols)
      85             : 
      86        1224 :       NULLIFY (work%a, work%a0, work%a_inv, work%b, work%c, work%d, work%e, work%scratch)
      87        1224 :       ALLOCATE (work%a, work%a0, work%a_inv, work%b, work%c, work%d, work%e, work%scratch)
      88        1224 :       CALL cp_cfm_create(work%a, fm_struct)
      89        1224 :       CALL cp_cfm_create(work%a0, fm_struct)
      90        1224 :       CALL cp_cfm_create(work%a_inv, fm_struct)
      91        1224 :       CALL cp_cfm_create(work%b, fm_struct)
      92        1224 :       CALL cp_cfm_create(work%c, fm_struct)
      93        1224 :       CALL cp_cfm_create(work%d, fm_struct)
      94        1224 :       CALL cp_cfm_create(work%e, fm_struct)
      95        1224 :       CALL cp_cfm_create(work%scratch, fm_struct)
      96             : 
      97        1224 :       CALL timestop(handle)
      98        1224 :    END SUBROUTINE sancho_work_matrices_create
      99             : 
     100             : ! **************************************************************************************************
     101             : !> \brief Release work matrices.
     102             : !> \param work   work matrices to release
     103             : !> \author Sergey Chulkov
     104             : ! **************************************************************************************************
     105        1224 :    SUBROUTINE sancho_work_matrices_release(work)
     106             :       TYPE(sancho_work_matrices_type), INTENT(inout)     :: work
     107             : 
     108             :       CHARACTER(len=*), PARAMETER :: routineN = 'sancho_work_matrices_release'
     109             : 
     110             :       INTEGER                                            :: handle
     111             : 
     112        1224 :       CALL timeset(routineN, handle)
     113             : 
     114        1224 :       IF (ASSOCIATED(work%a)) THEN
     115        1224 :          CALL cp_cfm_release(work%a)
     116        1224 :          DEALLOCATE (work%a)
     117             :          NULLIFY (work%a)
     118             :       END IF
     119        1224 :       IF (ASSOCIATED(work%a0)) THEN
     120        1224 :          CALL cp_cfm_release(work%a0)
     121        1224 :          DEALLOCATE (work%a0)
     122             :          NULLIFY (work%a0)
     123             :       END IF
     124        1224 :       IF (ASSOCIATED(work%a_inv)) THEN
     125        1224 :          CALL cp_cfm_release(work%a_inv)
     126        1224 :          DEALLOCATE (work%a_inv)
     127             :          NULLIFY (work%a_inv)
     128             :       END IF
     129        1224 :       IF (ASSOCIATED(work%b)) THEN
     130        1224 :          CALL cp_cfm_release(work%b)
     131        1224 :          DEALLOCATE (work%b)
     132             :          NULLIFY (work%b)
     133             :       END IF
     134        1224 :       IF (ASSOCIATED(work%c)) THEN
     135        1224 :          CALL cp_cfm_release(work%c)
     136        1224 :          DEALLOCATE (work%c)
     137             :          NULLIFY (work%c)
     138             :       END IF
     139        1224 :       IF (ASSOCIATED(work%d)) THEN
     140        1224 :          CALL cp_cfm_release(work%d)
     141        1224 :          DEALLOCATE (work%d)
     142             :          NULLIFY (work%d)
     143             :       END IF
     144        1224 :       IF (ASSOCIATED(work%e)) THEN
     145        1224 :          CALL cp_cfm_release(work%e)
     146        1224 :          DEALLOCATE (work%e)
     147             :          NULLIFY (work%e)
     148             :       END IF
     149        1224 :       IF (ASSOCIATED(work%scratch)) THEN
     150        1224 :          CALL cp_cfm_release(work%scratch)
     151        1224 :          DEALLOCATE (work%scratch)
     152             :          NULLIFY (work%scratch)
     153             :       END IF
     154             : 
     155        1224 :       CALL timestop(handle)
     156        1224 :    END SUBROUTINE sancho_work_matrices_release
     157             : 
     158             : ! **************************************************************************************************
     159             : !> \brief Iterative method to compute a retarded surface Green's function at the point omega.
     160             : !> \param g_surf   computed retarded surface Green's function (initialised on exit)
     161             : !> \param omega    argument of the Green's function
     162             : !> \param h0       diagonal block of the Kohn-Sham matrix (must be Hermitian)
     163             : !> \param s0       diagonal block of the overlap matrix (must be Hermitian)
     164             : !> \param h1       off-fiagonal block of the Kohn-Sham matrix
     165             : !> \param s1       off-fiagonal block of the overlap matrix
     166             : !> \param conv     convergence threshold
     167             : !> \param transp   flag which indicates that the matrices h1 and s1 matrices should be transposed
     168             : !> \param work     a set of work matrices needed to compute the surface Green's function
     169             : !> \author Sergey Chulkov
     170             : ! **************************************************************************************************
     171       13220 :    SUBROUTINE do_sancho(g_surf, omega, h0, s0, h1, s1, conv, transp, work)
     172             :       TYPE(cp_cfm_type), INTENT(IN)                      :: g_surf
     173             :       COMPLEX(kind=dp), INTENT(in)                       :: omega
     174             :       TYPE(cp_fm_type), INTENT(IN)                       :: h0, s0, h1, s1
     175             :       REAL(kind=dp), INTENT(in)                          :: conv
     176             :       LOGICAL, INTENT(in)                                :: transp
     177             :       TYPE(sancho_work_matrices_type), INTENT(in)        :: work
     178             : 
     179             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'do_sancho'
     180             : 
     181             :       INTEGER                                            :: handle, ncols, nrows
     182             : 
     183        6610 :       CALL timeset(routineN, handle)
     184             : 
     185        6610 :       CALL cp_cfm_get_info(g_surf, nrow_global=nrows, ncol_global=ncols)
     186             : 
     187             :       IF (debug_this_module) THEN
     188        6610 :          CPASSERT(nrows == ncols)
     189             :       END IF
     190             : 
     191             :       ! A^{ret.}_0 = omega * s0 - h0
     192        6610 :       CALL cp_fm_to_cfm(msourcer=s0, mtarget=work%a)
     193        6610 :       CALL cp_cfm_scale_and_add_fm(omega, work%a, z_mone, h0)
     194             :       ! A0^{ret.}_0 = A^{ret.}_0
     195        6610 :       CALL cp_cfm_to_cfm(work%a, work%a0)
     196             : 
     197             :       ! B^{ret.}_0 = omega * s1 - h1
     198             :       ! C^{ret.}_0 = B^{ret.}_0^T
     199        6610 :       IF (transp) THEN
     200             :          ! beta = omega * s1 - h1
     201        1260 :          CALL cp_fm_to_cfm(msourcer=s1, mtarget=work%c)
     202        1260 :          CALL cp_cfm_scale_and_add_fm(omega, work%c, z_mone, h1)
     203             : 
     204             :          ! alpha = omega * s1' - h1'
     205        1260 :          CALL cp_cfm_transpose(matrix=work%c, trans='T', matrixt=work%b)
     206             :       ELSE
     207             :          ! alpha  = omega * s1 - h1
     208        5350 :          CALL cp_fm_to_cfm(msourcer=s1, mtarget=work%b)
     209        5350 :          CALL cp_cfm_scale_and_add_fm(omega, work%b, z_mone, h1)
     210             : 
     211             :          ! beta = omega * s1' - h1'
     212        5350 :          CALL cp_cfm_transpose(matrix=work%b, trans='T', matrixt=work%c)
     213             :       END IF
     214             : 
     215             :       ! actually compute the Green's function
     216       44026 :       DO WHILE (cp_cfm_norm(work%b, 'M') + cp_cfm_norm(work%c, 'M') > conv)
     217             :          ! A_n^-1
     218       37416 :          CALL cp_cfm_to_cfm(work%a, work%a_inv)
     219       37416 :          CALL cp_cfm_lu_invert(work%a_inv)
     220             : 
     221             :          ! scratch <- A_n^-1 * B_n
     222       37416 :          CALL parallel_gemm('N', 'N', nrows, nrows, nrows, z_one, work%a_inv, work%b, z_zero, work%scratch)
     223             :          ! E_n = - C_n A_n^-1 B_n
     224       37416 :          CALL cp_cfm_gemm('N', 'N', nrows, nrows, nrows, z_mone, work%c, work%scratch, z_zero, work%e)
     225             :          ! g_surf <- B_{n+1} = B_n A_n^-1 B_n
     226             :          ! keep B_n, as we need it to compute the matrix product B_n A_n^-1 C_n
     227       37416 :          CALL parallel_gemm('N', 'N', nrows, nrows, nrows, z_one, work%b, work%scratch, z_zero, g_surf)
     228             : 
     229             :          ! scratch <- A_n^-1 * C_n
     230       37416 :          CALL parallel_gemm('N', 'N', nrows, nrows, nrows, z_one, work%a_inv, work%c, z_zero, work%scratch)
     231             :          ! D_n = - B_n A_n^-1 C_n
     232       37416 :          CALL cp_cfm_gemm('N', 'N', nrows, nrows, nrows, z_mone, work%b, work%scratch, z_zero, work%d)
     233             :          ! we do not need B_n any longer, so the matrix B now holds the B_{n+1} matrix
     234       37416 :          CALL cp_cfm_to_cfm(g_surf, work%b)
     235             :          ! C_{n+1} = C_n A_n^-1 C_n
     236       37416 :          CALL parallel_gemm('N', 'N', nrows, nrows, nrows, z_one, work%c, work%scratch, z_zero, g_surf)
     237       37416 :          CALL cp_cfm_to_cfm(g_surf, work%c)
     238             : 
     239             :          ! A0_{n+1} = A0_n + D_n = A0_n - B_n A_n^-1 C_n
     240       37416 :          CALL cp_cfm_scale_and_add(z_one, work%a0, z_one, work%d)
     241             : 
     242             :          ! A_{n+1} = A0_n + D_n + E_n = A_n - B_n A_n^-1 C_n - C_n A_n^-1 B_n
     243       37416 :          CALL cp_cfm_scale_and_add(z_one, work%a, z_one, work%d)
     244       44026 :          CALL cp_cfm_scale_and_add(z_one, work%a, z_one, work%e)
     245             :       END DO
     246             : 
     247             :       ! g_surf = A0_n^-1
     248        6610 :       CALL cp_cfm_to_cfm(work%a0, g_surf)
     249        6610 :       CALL cp_cfm_lu_invert(g_surf)
     250             : 
     251        6610 :       CALL timestop(handle)
     252        6610 :    END SUBROUTINE do_sancho
     253             : 
     254             : ! **************************************************************************************************
     255             : !> \brief Compute the contact self energy at point 'omega' as
     256             : !>   self_energy_C = [omega * S_SC0 - KS_SC0] * g_surf_c(omega - v_C) * [omega * S_SC0 - KS_SC0]^T,
     257             : !>   where C stands for the left (L) / right (R) contact.
     258             : !> \param self_energy_c contact self energy (initialised on exit)
     259             : !> \param omega         energy point where the contact self energy needs to be computed
     260             : !> \param g_surf_c      contact surface Green's function
     261             : !> \param h_sc0         scattering region -- contact off-diagonal block of the Kohn-Sham matrix
     262             : !> \param s_sc0         scattering region -- contact off-diagonal block of the overlap matrix
     263             : !> \param zwork1        complex work matrix of the same shape as s_sc0
     264             : !> \param zwork2        another complex work matrix of the same shape as s_sc0
     265             : !> \param transp        flag which indicates that transposed matrices (KS_C0S and S_C0S)
     266             : !>                      were actually passed
     267             : !> \author Sergey Chulkov
     268             : ! **************************************************************************************************
     269       11534 :    SUBROUTINE negf_contact_self_energy(self_energy_c, omega, g_surf_c, h_sc0, s_sc0, zwork1, zwork2, transp)
     270             :       TYPE(cp_cfm_type), INTENT(IN)                      :: self_energy_c
     271             :       COMPLEX(kind=dp), INTENT(in)                       :: omega
     272             :       TYPE(cp_cfm_type), INTENT(IN)                      :: g_surf_c
     273             :       TYPE(cp_fm_type), INTENT(IN)                       :: h_sc0, s_sc0
     274             :       TYPE(cp_cfm_type), INTENT(IN)                      :: zwork1, zwork2
     275             :       LOGICAL, INTENT(in)                                :: transp
     276             : 
     277             :       CHARACTER(len=*), PARAMETER :: routineN = 'negf_contact_self_energy'
     278             : 
     279             :       INTEGER                                            :: handle, nao_contact, nao_scattering
     280             : 
     281       11534 :       CALL timeset(routineN, handle)
     282             : 
     283             :       ! zwork1 = omega * S_SC0   - KS_SC0     if transp = .FALSE., or
     284             :       !        = omega * S_SC0^T - KS_SC0^T   if transp = .TRUE.
     285       11534 :       CALL cp_fm_to_cfm(msourcer=s_sc0, mtarget=zwork1)
     286       11534 :       CALL cp_cfm_scale_and_add_fm(omega, zwork1, z_mone, h_sc0)
     287             : 
     288       11534 :       IF (transp) THEN
     289        1260 :          CALL cp_fm_get_info(s_sc0, nrow_global=nao_contact, ncol_global=nao_scattering)
     290             : 
     291             :          ! zwork2 = g_surf_c * [omega * S_SC0^T - KS_SC0^T]
     292        1260 :          CALL parallel_gemm('N', 'N', nao_contact, nao_scattering, nao_contact, z_one, g_surf_c, zwork1, z_zero, zwork2)
     293             :          ! [omega * S_SC0^T - KS_SC0^T]^T * g_surf_c * [omega * S_SC0^T - KS_SC0^T]
     294        1260 :          CALL parallel_gemm('T', 'N', nao_scattering, nao_scattering, nao_contact, z_one, zwork1, zwork2, z_zero, self_energy_c)
     295             :       ELSE
     296       10274 :          CALL cp_fm_get_info(s_sc0, nrow_global=nao_scattering, ncol_global=nao_contact)
     297             : 
     298             :          ! zwork2 = [omega * S_SC0 - KS_SC0] * g_surf_c
     299       10274 :          CALL parallel_gemm('N', 'N', nao_scattering, nao_contact, nao_contact, z_one, zwork1, g_surf_c, z_zero, zwork2)
     300             :          ! [omega * S_SC0 - KS_SC0] * g_surf_c * [omega * S_SC0 - KS_SC0]^T
     301       10274 :          CALL parallel_gemm('N', 'T', nao_scattering, nao_scattering, nao_contact, z_one, zwork2, zwork1, z_zero, self_energy_c)
     302             :       END IF
     303             : 
     304       11534 :       CALL timestop(handle)
     305       11534 :    END SUBROUTINE negf_contact_self_energy
     306             : 
     307             : ! **************************************************************************************************
     308             : !> \brief Compute contact broadening matrix as
     309             : !>   gamma_C = i (self_energy_c^{ret.} - (self_energy_c^{ret.})^C)
     310             : !> \param gamma_c            broadening matrix (initialised on exit)
     311             : !> \param self_energy_c      retarded contact self-energy
     312             : !> \author Sergey Chulkov
     313             : ! **************************************************************************************************
     314        1230 :    SUBROUTINE negf_contact_broadening_matrix(gamma_c, self_energy_c)
     315             :       TYPE(cp_cfm_type), INTENT(IN)                      :: gamma_c, self_energy_c
     316             : 
     317             :       CHARACTER(len=*), PARAMETER :: routineN = 'negf_contact_broadening_matrix'
     318             : 
     319             :       INTEGER                                            :: handle
     320             : 
     321        1230 :       CALL timeset(routineN, handle)
     322             : 
     323             :       ! gamma_contact = i (self_energy_contact^{ret.} - self_energy_contact^{adv.}) .
     324             :       !
     325             :       ! With no k-points, the Hamiltonian matrix is real-values, so
     326             :       ! self_energy_contact^{adv.} = self_energy_contact^{ret.}^C ,
     327             :       ! The above identity allows us to use a simplified expression for the broadening matrix:
     328             :       ! gamma_contact = i [self_energy_contact - self_energy_contact^C] .
     329             : 
     330        1230 :       CALL cp_cfm_transpose(self_energy_c, 'C', gamma_c)
     331        1230 :       CALL cp_cfm_scale_and_add(z_mone, gamma_c, z_one, self_energy_c)
     332        1230 :       CALL cp_cfm_scale(gaussi, gamma_c)
     333             : 
     334        1230 :       CALL timestop(handle)
     335        1230 :    END SUBROUTINE negf_contact_broadening_matrix
     336             : 
     337             : ! **************************************************************************************************
     338             : !> \brief Compute the retarded Green's function at point 'omega' as
     339             : !>   G_S^{ret.} = [ omega * S_S - KS_S - \sum_{contact} self_energy_{contact}^{ret.}]^{-1}.
     340             : !> \param g_ret_s            complex matrix to store the computed retarded Green's function
     341             : !> \param omega              energy point where the retarded Green's function needs to be computed
     342             : !> \param self_energy_ret_sum sum of contact self-energies
     343             : !> \param h_s                Kohn-Sham matrix block of the scattering region
     344             : !> \param s_s                overlap matrix block of the scattering region
     345             : !> \param v_hartree_s        contribution to the Kohn-Sham matrix from the external potential
     346             : !> \author Sergey Chulkov
     347             : ! **************************************************************************************************
     348        5767 :    SUBROUTINE negf_retarded_green_function(g_ret_s, omega, self_energy_ret_sum, h_s, s_s, v_hartree_s)
     349             :       TYPE(cp_cfm_type), INTENT(IN)                      :: g_ret_s
     350             :       COMPLEX(kind=dp), INTENT(in)                       :: omega
     351             :       TYPE(cp_cfm_type), INTENT(IN)                      :: self_energy_ret_sum
     352             :       TYPE(cp_fm_type), INTENT(IN)                       :: h_s, s_s
     353             :       TYPE(cp_fm_type), INTENT(IN), OPTIONAL             :: v_hartree_s
     354             : 
     355             :       CHARACTER(len=*), PARAMETER :: routineN = 'negf_retarded_green_function'
     356             : 
     357             :       INTEGER                                            :: handle
     358             : 
     359        5767 :       CALL timeset(routineN, handle)
     360             : 
     361             :       ! g_ret_s = [ omega * S_S - H_S - self_energy_left - self_energy_right]^{-1}
     362             :       !
     363             :       ! omega * S_S - H_S - V_Hartree
     364        5767 :       CALL cp_fm_to_cfm(msourcer=s_s, mtarget=g_ret_s)
     365        5767 :       CALL cp_cfm_scale_and_add_fm(omega, g_ret_s, z_mone, h_s)
     366        5767 :       IF (PRESENT(v_hartree_s)) &
     367        1597 :          CALL cp_cfm_scale_and_add_fm(z_one, g_ret_s, z_one, v_hartree_s)
     368             : 
     369             :       ! g_ret_s = [omega * S_S - H_S - \sum_{contact} self_energy_{contact}^{ret.} ]^-1
     370        5767 :       CALL cp_cfm_scale_and_add(z_one, g_ret_s, z_mone, self_energy_ret_sum)
     371             : 
     372        5767 :       CALL cp_cfm_lu_invert(g_ret_s)
     373             : 
     374        5767 :       CALL timestop(handle)
     375        5767 :    END SUBROUTINE negf_retarded_green_function
     376           0 : END MODULE negf_green_methods
     377             : 

Generated by: LCOV version 1.15