(git:34ef472)
negf_green_methods.F
Go to the documentation of this file.
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 ! **************************************************************************************************
12  USE cp_cfm_basic_linalg, ONLY: cp_cfm_gemm,&
14  cp_cfm_norm,&
15  cp_cfm_scale,&
19  USE cp_cfm_types, ONLY: cp_cfm_create,&
22  cp_cfm_to_cfm,&
23  cp_cfm_type,&
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
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  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  CALL timeset(routinen, handle)
81  cpassert(ASSOCIATED(fm_struct))
82 
83  CALL cp_fm_struct_get(fm_struct, nrow_global=nrows, ncol_global=ncols)
84  cpassert(nrows == ncols)
85 
86  NULLIFY (work%a, work%a0, work%a_inv, work%b, work%c, work%d, work%e, work%scratch)
87  ALLOCATE (work%a, work%a0, work%a_inv, work%b, work%c, work%d, work%e, work%scratch)
88  CALL cp_cfm_create(work%a, fm_struct)
89  CALL cp_cfm_create(work%a0, fm_struct)
90  CALL cp_cfm_create(work%a_inv, fm_struct)
91  CALL cp_cfm_create(work%b, fm_struct)
92  CALL cp_cfm_create(work%c, fm_struct)
93  CALL cp_cfm_create(work%d, fm_struct)
94  CALL cp_cfm_create(work%e, fm_struct)
95  CALL cp_cfm_create(work%scratch, fm_struct)
96 
97  CALL timestop(handle)
98  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 ! **************************************************************************************************
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  CALL timeset(routinen, handle)
113 
114  IF (ASSOCIATED(work%a)) THEN
115  CALL cp_cfm_release(work%a)
116  DEALLOCATE (work%a)
117  NULLIFY (work%a)
118  END IF
119  IF (ASSOCIATED(work%a0)) THEN
120  CALL cp_cfm_release(work%a0)
121  DEALLOCATE (work%a0)
122  NULLIFY (work%a0)
123  END IF
124  IF (ASSOCIATED(work%a_inv)) THEN
125  CALL cp_cfm_release(work%a_inv)
126  DEALLOCATE (work%a_inv)
127  NULLIFY (work%a_inv)
128  END IF
129  IF (ASSOCIATED(work%b)) THEN
130  CALL cp_cfm_release(work%b)
131  DEALLOCATE (work%b)
132  NULLIFY (work%b)
133  END IF
134  IF (ASSOCIATED(work%c)) THEN
135  CALL cp_cfm_release(work%c)
136  DEALLOCATE (work%c)
137  NULLIFY (work%c)
138  END IF
139  IF (ASSOCIATED(work%d)) THEN
140  CALL cp_cfm_release(work%d)
141  DEALLOCATE (work%d)
142  NULLIFY (work%d)
143  END IF
144  IF (ASSOCIATED(work%e)) THEN
145  CALL cp_cfm_release(work%e)
146  DEALLOCATE (work%e)
147  NULLIFY (work%e)
148  END IF
149  IF (ASSOCIATED(work%scratch)) THEN
150  CALL cp_cfm_release(work%scratch)
151  DEALLOCATE (work%scratch)
152  NULLIFY (work%scratch)
153  END IF
154 
155  CALL timestop(handle)
156  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  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  CALL timeset(routinen, handle)
184 
185  CALL cp_cfm_get_info(g_surf, nrow_global=nrows, ncol_global=ncols)
186 
187  IF (debug_this_module) THEN
188  cpassert(nrows == ncols)
189  END IF
190 
191  ! A^{ret.}_0 = omega * s0 - h0
192  CALL cp_fm_to_cfm(msourcer=s0, mtarget=work%a)
193  CALL cp_cfm_scale_and_add_fm(omega, work%a, z_mone, h0)
194  ! A0^{ret.}_0 = A^{ret.}_0
195  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  IF (transp) THEN
200  ! beta = omega * s1 - h1
201  CALL cp_fm_to_cfm(msourcer=s1, mtarget=work%c)
202  CALL cp_cfm_scale_and_add_fm(omega, work%c, z_mone, h1)
203 
204  ! alpha = omega * s1' - h1'
205  CALL cp_cfm_transpose(matrix=work%c, trans='T', matrixt=work%b)
206  ELSE
207  ! alpha = omega * s1 - h1
208  CALL cp_fm_to_cfm(msourcer=s1, mtarget=work%b)
209  CALL cp_cfm_scale_and_add_fm(omega, work%b, z_mone, h1)
210 
211  ! beta = omega * s1' - h1'
212  CALL cp_cfm_transpose(matrix=work%b, trans='T', matrixt=work%c)
213  END IF
214 
215  ! actually compute the Green's function
216  DO WHILE (cp_cfm_norm(work%b, 'M') + cp_cfm_norm(work%c, 'M') > conv)
217  ! A_n^-1
218  CALL cp_cfm_to_cfm(work%a, work%a_inv)
219  CALL cp_cfm_lu_invert(work%a_inv)
220 
221  ! scratch <- A_n^-1 * B_n
222  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  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  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  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  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  CALL cp_cfm_to_cfm(g_surf, work%b)
235  ! C_{n+1} = C_n A_n^-1 C_n
236  CALL parallel_gemm('N', 'N', nrows, nrows, nrows, z_one, work%c, work%scratch, z_zero, g_surf)
237  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  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  CALL cp_cfm_scale_and_add(z_one, work%a, z_one, work%d)
244  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  CALL cp_cfm_to_cfm(work%a0, g_surf)
249  CALL cp_cfm_lu_invert(g_surf)
250 
251  CALL timestop(handle)
252  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  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  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  CALL cp_fm_to_cfm(msourcer=s_sc0, mtarget=zwork1)
286  CALL cp_cfm_scale_and_add_fm(omega, zwork1, z_mone, h_sc0)
287 
288  IF (transp) THEN
289  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  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  CALL parallel_gemm('T', 'N', nao_scattering, nao_scattering, nao_contact, z_one, zwork1, zwork2, z_zero, self_energy_c)
295  ELSE
296  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  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  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  CALL timestop(handle)
305  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  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  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  CALL cp_cfm_transpose(self_energy_c, 'C', gamma_c)
331  CALL cp_cfm_scale_and_add(z_mone, gamma_c, z_one, self_energy_c)
332  CALL cp_cfm_scale(gaussi, gamma_c)
333 
334  CALL timestop(handle)
335  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  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  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  CALL cp_fm_to_cfm(msourcer=s_s, mtarget=g_ret_s)
365  CALL cp_cfm_scale_and_add_fm(omega, g_ret_s, z_mone, h_s)
366  IF (PRESENT(v_hartree_s)) &
367  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  CALL cp_cfm_scale_and_add(z_one, g_ret_s, z_mone, self_energy_ret_sum)
371 
372  CALL cp_cfm_lu_invert(g_ret_s)
373 
374  CALL timestop(handle)
375  END SUBROUTINE negf_retarded_green_function
376 END MODULE negf_green_methods
377 
Basic linear algebra operations for complex full matrices.
subroutine, public cp_cfm_scale_and_add(alpha, matrix_a, beta, matrix_b)
Scale and add two BLACS matrices (a = alpha*a + beta*b).
subroutine, public cp_cfm_lu_invert(matrix, info_out)
Inverts a matrix using LU decomposition. The input matrix will be overwritten.
real(kind=dp) function, public cp_cfm_norm(matrix, mode)
Norm of matrix using (p)zlange.
subroutine, public cp_cfm_gemm(transa, transb, m, n, k, alpha, matrix_a, matrix_b, beta, matrix_c, a_first_col, a_first_row, b_first_col, b_first_row, c_first_col, c_first_row)
Performs one of the matrix-matrix operations: matrix_c = alpha * op1( matrix_a ) * op2( matrix_b ) + ...
subroutine, public cp_cfm_transpose(matrix, trans, matrixt)
Transposes a BLACS distributed complex matrix.
subroutine, public cp_cfm_scale_and_add_fm(alpha, matrix_a, beta, matrix_b)
Scale and add two BLACS matrices (a = alpha*a + beta*b). where b is a real matrix (adapted from cp_cf...
Represents a complex full matrix distributed on many processors.
Definition: cp_cfm_types.F:12
subroutine, public cp_cfm_create(matrix, matrix_struct, name)
Creates a new full matrix with the given structure.
Definition: cp_cfm_types.F:121
subroutine, public cp_cfm_release(matrix)
Releases a full matrix.
Definition: cp_cfm_types.F:159
subroutine, public cp_fm_to_cfm(msourcer, msourcei, mtarget)
Construct a complex full matrix by taking its real and imaginary parts from two separate real-value f...
Definition: cp_cfm_types.F:817
subroutine, public cp_cfm_get_info(matrix, name, nrow_global, ncol_global, nrow_block, ncol_block, nrow_local, ncol_local, row_indices, col_indices, local_data, context, matrix_struct, para_env)
Returns information about a full matrix.
Definition: cp_cfm_types.F:607
represent the structure of a full matrix
Definition: cp_fm_struct.F:14
subroutine, public cp_fm_struct_get(fmstruct, para_env, context, descriptor, ncol_block, nrow_block, nrow_global, ncol_global, first_p_pos, row_indices, col_indices, nrow_local, ncol_local, nrow_locals, ncol_locals, local_leading_dimension)
returns the values of various attributes of the matrix structure
Definition: cp_fm_struct.F:409
represent a full matrix distributed on many processors
Definition: cp_fm_types.F:15
subroutine, public cp_fm_get_info(matrix, name, nrow_global, ncol_global, nrow_block, ncol_block, nrow_local, ncol_local, row_indices, col_indices, local_data, context, nrow_locals, ncol_locals, matrix_struct, para_env)
returns all kind of information about the full matrix
Definition: cp_fm_types.F:1016
Defines the basic variable types.
Definition: kinds.F:23
integer, parameter, public dp
Definition: kinds.F:34
Definition of mathematical constants and functions.
Definition: mathconstants.F:16
complex(kind=dp), parameter, public z_mone
complex(kind=dp), parameter, public z_one
complex(kind=dp), parameter, public gaussi
complex(kind=dp), parameter, public z_zero
Subroutines to compute Green functions.
subroutine, public sancho_work_matrices_create(work, fm_struct)
Create work matrices required for the Lopez-Sancho algorithm.
subroutine, public sancho_work_matrices_release(work)
Release work matrices.
subroutine, public negf_contact_self_energy(self_energy_c, omega, g_surf_c, h_sc0, s_sc0, zwork1, zwork2, transp)
Compute the contact self energy at point 'omega' as self_energy_C = [omega * S_SC0 - KS_SC0] * g_surf...
subroutine, public negf_contact_broadening_matrix(gamma_c, self_energy_c)
Compute contact broadening matrix as gamma_C = i (self_energy_c^{ret.} - (self_energy_c^{ret....
subroutine, public do_sancho(g_surf, omega, h0, s0, h1, s1, conv, transp, work)
Iterative method to compute a retarded surface Green's function at the point omega.
subroutine, public negf_retarded_green_function(g_ret_s, omega, self_energy_ret_sum, h_s, s_s, v_hartree_s)
Compute the retarded Green's function at point 'omega' as G_S^{ret.} = [ omega * S_S - KS_S - \sum_{c...
basic linear algebra operations for full matrixes