Line data Source code
1 : !!****m* ABINIT/m_gwls_LanczosResolvents
2 : !! NAME
3 : !! m_gwls_LanczosResolvents
4 : !!
5 : !! FUNCTION
6 : !! .
7 : !!
8 : !! COPYRIGHT
9 : !! Copyright (C) 2009-2026 ABINIT group (JLJ, BR, MC)
10 : !! This file is distributed under the terms of the
11 : !! GNU General Public License, see ~abinit/COPYING
12 : !! or http://www.gnu.org/copyleft/gpl.txt .
13 : !!
14 : !! SOURCE
15 :
16 : #if defined HAVE_CONFIG_H
17 : #include "config.h"
18 : #endif
19 :
20 : #include "abi_common.h"
21 :
22 :
23 : module m_gwls_LanczosResolvents
24 : !----------------------------------------------------------------------------------------------------
25 : ! This module contains routines to compute the matrix elements of the resolent, namely
26 : !
27 : ! < phi_l | 1/ (H-z) | psi_l' >
28 : !
29 : ! where H is the Hamiltonian, and z should be such that we are far from its poles.
30 : !
31 : !----------------------------------------------------------------------------------------------------
32 : ! local modules
33 :
34 : use m_gwls_utility
35 : use m_gwls_wf
36 : use m_gwls_TimingLog
37 : use m_gwls_hamiltonian
38 : use m_gwls_lineqsolver
39 : use m_gwls_GWlanczos
40 :
41 : use defs_basis
42 : use m_abicore
43 : use m_xmpi
44 : use m_io_tools, only : get_unit
45 :
46 : implicit none
47 : save
48 : private
49 : !!***
50 :
51 :
52 : integer :: LR_kmax, LR_nseeds
53 :
54 : complex(dp), allocatable :: precondition_C(:) ! this operator is diagonal!
55 : complex(dp), allocatable :: precondition_one_on_C(:) ! this operator is diagonal!
56 :
57 :
58 : complex(dp), allocatable, public :: Hamiltonian_Qk(:,:) ! Lanczos basis of the Hamiltonian
59 :
60 : complex(dp), allocatable :: LR_alpha(:,:,:)
61 : complex(dp), allocatable :: LR_beta (:,:,:)
62 : complex(dp), allocatable :: LR_seeds(:,:)
63 : real(dp), allocatable :: LR_Hamiltonian_eigenvalues(:)
64 :
65 : complex(dp), allocatable, public :: LR_M_matrix(:,:)
66 : !!***
67 :
68 : public :: setup_LanczosResolvents
69 : public :: cleanup_LanczosResolvents
70 : public :: compute_resolvent_column_shift_lanczos
71 : public :: compute_resolvent_column_shift_lanczos_right_vectors
72 : public :: build_preconditioned_Hamiltonian_Lanczos_basis
73 : public :: invert_general_matrix
74 : !!***
75 :
76 : contains
77 :
78 :
79 : !!****f* m_hamiltonian/setup_LanczosResolvents
80 : !! NAME
81 : !! setup_LanczosResolvents
82 : !!
83 : !! FUNCTION
84 : !! .
85 : !!
86 : !! INPUTS
87 : !!
88 : !! OUTPUT
89 : !!
90 : !! SOURCE
91 :
92 26 : subroutine setup_LanczosResolvents(kmax, prec)
93 : !----------------------------------------------------------------------------------------------------
94 : !
95 : ! This subroutine prepares global work arrays in order to use the Lanczos scheme to
96 : ! compute matrix elements of inverse operators.
97 : !
98 : !
99 : !----------------------------------------------------------------------------------------------------
100 : implicit none
101 :
102 : !------------------------------
103 : ! input/output variables
104 : !------------------------------
105 :
106 : integer, intent(in) :: kmax ! number of Lanczos steps
107 : logical, intent(in) :: prec ! should there be preconditioning?
108 :
109 : ! *************************************************************************
110 :
111 :
112 26 : LR_kmax = kmax
113 26 : LR_nseeds = 1 ! only one seed
114 :
115 : ! Prepare the algorithm
116 :
117 78 : ABI_MALLOC(precondition_C, (npw_g))
118 52 : ABI_MALLOC(precondition_one_on_C, (npw_g))
119 :
120 :
121 26 : if ( prec ) then
122 0 : call set_precondition()
123 :
124 0 : precondition_one_on_C(:) = sqrt(pcon(:))
125 : !precondition_one_on_C(:) = pcon(:) ! yields very bad results!
126 0 : precondition_C(:) = cmplx_1/precondition_one_on_C(:)
127 :
128 : else
129 4652 : precondition_C(:) = cmplx_1
130 4652 : precondition_one_on_C(:) = cmplx_1
131 : end if
132 :
133 130 : ABI_MALLOC(LR_alpha, (LR_nseeds,LR_nseeds,LR_kmax))
134 104 : ABI_MALLOC(LR_beta , (LR_nseeds,LR_nseeds,LR_kmax))
135 104 : ABI_MALLOC(LR_seeds, (npw_g,LR_nseeds))
136 104 : ABI_MALLOC(Hamiltonian_Qk, (npw_g,LR_kmax))
137 78 : ABI_MALLOC(LR_Hamiltonian_eigenvalues, (LR_kmax))
138 104 : ABI_MALLOC(LR_M_matrix, (LR_kmax,LR_kmax))
139 :
140 26 : end subroutine setup_LanczosResolvents
141 : !!***
142 :
143 : !!****f* m_hamiltonian/cleanup_LanczosResolvents
144 : !! NAME
145 : !! cleanup_LanczosResolvents
146 : !!
147 : !! FUNCTION
148 : !! .
149 : !!
150 : !! INPUTS
151 : !!
152 : !! OUTPUT
153 : !!
154 : !! SOURCE
155 :
156 26 : subroutine cleanup_LanczosResolvents
157 : !----------------------------------------------------------------------------------------------------
158 : !
159 : ! This subroutine cleans up global arrays.
160 : !
161 : !
162 : !----------------------------------------------------------------------------------------------------
163 : implicit none
164 :
165 : ! *************************************************************************
166 :
167 26 : ABI_FREE(precondition_C)
168 26 : ABI_FREE(precondition_one_on_C)
169 26 : ABI_FREE(LR_alpha)
170 26 : ABI_FREE(LR_beta )
171 26 : ABI_FREE(LR_seeds)
172 26 : ABI_FREE(Hamiltonian_Qk)
173 26 : ABI_FREE(LR_Hamiltonian_eigenvalues)
174 26 : ABI_FREE(LR_M_matrix)
175 :
176 26 : end subroutine cleanup_LanczosResolvents
177 : !!***
178 :
179 : !!****f* m_hamiltonian/matrix_function_preconditioned_Hamiltonian
180 : !! NAME
181 : !! matrix_function_preconditioned_Hamiltonian
182 : !!
183 : !! FUNCTION
184 : !! .
185 : !!
186 : !! INPUTS
187 : !!
188 : !! OUTPUT
189 : !!
190 : !! SOURCE
191 :
192 1728 : subroutine matrix_function_preconditioned_Hamiltonian(vector_out,vector_in,Hsize)
193 : !----------------------------------------------------------------------------------------------------
194 : ! This subroutine is a simple wrapper around the preconditioned Hamiltonian operator which acts as
195 : !
196 : ! C^{-1} . H . C^{-1}
197 : !
198 : ! where C^{-2} ~ 1 / T, where T is the kinetic energy.
199 : !
200 : !----------------------------------------------------------------------------------------------------
201 : implicit none
202 : integer, intent(in) :: Hsize
203 : complex(dp), intent(out) :: vector_out(Hsize)
204 : complex(dp), intent(in) :: vector_in(Hsize)
205 :
206 : ! local variables
207 3456 : real(dp) :: psikg(2,npw_g)
208 :
209 3456 : complex(dp) :: tmp_vector(Hsize)
210 :
211 : ! *************************************************************************
212 :
213 : ! convert from one format to the other
214 :
215 347136 : tmp_vector(:) = precondition_one_on_C(:)*vector_in(:)
216 :
217 347136 : psikg(1,:) = dble (tmp_vector(:))
218 347136 : psikg(2,:) = dimag(tmp_vector(:))
219 :
220 1728 : call Hpsik(psikg)
221 :
222 347136 : tmp_vector(:) = cmplx_1*psikg(1,:)+cmplx_i*psikg(2,:)
223 :
224 347136 : vector_out(:) = precondition_one_on_C(:)*tmp_vector(:)
225 :
226 :
227 1728 : end subroutine matrix_function_preconditioned_Hamiltonian
228 : !!***
229 :
230 : !!****f* m_hamiltonian/build_preconditioned_Hamiltonian_Lanczos_basis
231 : !! NAME
232 : !! build_preconditioned_Hamiltonian_Lanczos_basis
233 : !!
234 : !! FUNCTION
235 : !! .
236 : !!
237 : !! INPUTS
238 : !!
239 : !! OUTPUT
240 : !!
241 : !! SOURCE
242 :
243 288 : subroutine build_preconditioned_Hamiltonian_Lanczos_basis(seed_vector)
244 : !----------------------------------------------------------------------------------------------------
245 : ! This function Computes the Lanczos basis of the preconditioned Hamiltonian.
246 : !----------------------------------------------------------------------------------------------------
247 : implicit none
248 : complex(dp), intent(in) :: seed_vector(npw_g)
249 :
250 : integer :: l
251 : integer :: ierr
252 : integer :: mpi_communicator
253 :
254 : ! *************************************************************************
255 :
256 :
257 :
258 144 : mpi_communicator = mpi_enreg%comm_fft
259 :
260 : ! Compute the Lanczos basis as well as the eigenvalues of the T matrix
261 : ! Seed must also be preconditioned!
262 28928 : LR_seeds(:,1) = precondition_one_on_C(:)*seed_vector(:)
263 :
264 : call block_lanczos_algorithm(mpi_communicator, matrix_function_preconditioned_Hamiltonian, LR_kmax, LR_nseeds, npw_g, LR_seeds, &
265 144 : & LR_alpha, LR_beta, Hamiltonian_Qk)
266 :
267 :
268 : call diagonalize_lanczos_banded(LR_kmax,LR_nseeds,npw_g, LR_alpha,LR_beta, &
269 144 : Hamiltonian_Qk, LR_Hamiltonian_eigenvalues,.false.)
270 :
271 :
272 :
273 : ! Update the Lanczos vectors with the preconditioning matrix
274 1872 : do l = 1, LR_kmax
275 347280 : Hamiltonian_Qk(:,l) = precondition_C(:)*Hamiltonian_Qk(:,l)
276 : end do
277 :
278 : ! compute the M matrix
279 :
280 : ! Compute Q^dagger . Q
281 144 : call ZGEMM('C','N',LR_kmax,LR_kmax,npw_g,cmplx_1,Hamiltonian_Qk,npw_g,Hamiltonian_Qk,npw_g,cmplx_0,LR_M_matrix,LR_kmax)
282 144 : call xmpi_sum(LR_M_matrix,mpi_communicator,ierr) ! sum on all processors working on FFT!
283 :
284 1872 : do l = 1, LR_kmax
285 24912 : LR_M_matrix(l,:) = LR_M_matrix(l,:)*LR_Hamiltonian_eigenvalues(l)
286 : end do
287 :
288 144 : end subroutine build_preconditioned_Hamiltonian_Lanczos_basis
289 : !!***
290 :
291 :
292 : !!****f* m_hamiltonian/compute_resolvent_column_shift_lanczos
293 : !! NAME
294 : !! compute_resolvent_column_shift_lanczos
295 : !!
296 : !! FUNCTION
297 : !! .
298 : !!
299 : !! INPUTS
300 : !!
301 : !! OUTPUT
302 : !!
303 : !! SOURCE
304 :
305 72 : subroutine compute_resolvent_column_shift_lanczos(nz, list_z, nvec, list_left_vectors, seed_vector, matrix_elements_resolvent)
306 : !----------------------------------------------------------------------------------------------------
307 : ! This function Computes one column of the resolvent using the shift lanczos algorithm,
308 : ! namely
309 : !
310 : !
311 : ! I_l(z) = < left_vector_l | xi(z) >
312 : !
313 : ! where |xi(z) > is obtained from the shift lanczos scheme.
314 : !----------------------------------------------------------------------------------------------------
315 : implicit none
316 :
317 : integer , intent(in) :: nz
318 : complex(dp), intent(in) :: list_z(nz)
319 :
320 : integer , intent(in) :: nvec
321 : complex(dp), intent(in) :: list_left_vectors(npw_g,nvec)
322 :
323 : complex(dp), intent(in) :: seed_vector(npw_g)
324 :
325 : complex(dp), intent(out) :: matrix_elements_resolvent(nz,nvec)
326 :
327 : ! local variables
328 : integer :: iz, l
329 : complex(dp) :: z
330 : integer :: ierr
331 : integer :: mpi_communicator
332 :
333 144 : complex(dp) :: right_vec(LR_kmax)
334 144 : complex(dp) :: left_vecs(LR_kmax,nvec)
335 144 : complex(dp) :: work_vec(LR_kmax)
336 144 : complex(dp) :: shift_lanczos_matrix(LR_kmax,LR_kmax)
337 :
338 144 : complex(dp) :: work_array(npw_g)
339 :
340 : ! *************************************************************************
341 :
342 :
343 : ! processes will communicate along FFT rows
344 72 : mpi_communicator = mpi_enreg%comm_fft
345 :
346 : !----------------------------------------------------------------------------------------------------
347 : ! First, build the Lanczos basis for the preconditioned Hamiltonian
348 : !----------------------------------------------------------------------------------------------------
349 72 : call build_preconditioned_Hamiltonian_Lanczos_basis(seed_vector)
350 :
351 :
352 : !----------------------------------------------------------------------------------------------------
353 : ! Next, generate arrays which do not depend on z, the external shift.
354 : !----------------------------------------------------------------------------------------------------
355 :
356 : ! Q^dagger . C^{-2} | seed >
357 14464 : work_array(:) = precondition_one_on_C(:)**2*seed_vector
358 :
359 72 : call ZGEMV('C',npw_g,LR_kmax,cmplx_1,Hamiltonian_Qk,npw_g,work_array,1,cmplx_0,right_vec,1)
360 72 : call xmpi_sum(right_vec,mpi_communicator,ierr) ! sum on all processors working on FFT!
361 :
362 : ! Q^dagger | left_vectors >
363 72 : call ZGEMM('C','N',LR_kmax,nvec,npw_g,cmplx_1,Hamiltonian_Qk,npw_g,list_left_vectors,npw_g,cmplx_0,left_vecs,LR_kmax)
364 72 : call xmpi_sum(left_vecs,mpi_communicator,ierr) ! sum on all processors working on FFT!
365 :
366 : !----------------------------------------------------------------------------------------------------
367 : ! Use shift Lanczos to compute all matrix elements!
368 : !----------------------------------------------------------------------------------------------------
369 :
370 144 : do iz = 1, nz
371 :
372 72 : z = list_z(iz)
373 :
374 : ! Generate the matrix to be inverted
375 5256 : shift_lanczos_matrix(:,:) = LR_M_matrix(:,:)
376 :
377 648 : do l = 1, LR_kmax
378 648 : shift_lanczos_matrix(l,l) = shift_lanczos_matrix(l,l)-z
379 : end do
380 :
381 : ! since z could be complex, the matrix is not necessarily hermitian. Invert using general Lapack scheme
382 72 : call invert_general_matrix(LR_kmax,shift_lanczos_matrix)
383 : ! the matrix now contains the inverse!
384 :
385 :
386 : ! | work_vec > = M^{-1} . | right_vec >
387 72 : call ZGEMV('N',LR_kmax,LR_kmax,cmplx_1,shift_lanczos_matrix,LR_kmax,right_vec,1,cmplx_0,work_vec,1)
388 :
389 :
390 : ! matrix_elements = < right_vecs | work_vec >
391 144 : call ZGEMV('C',LR_kmax,nvec,cmplx_1,left_vecs,LR_kmax,work_vec,1,cmplx_0,matrix_elements_resolvent(iz,:),1)
392 :
393 : end do
394 :
395 :
396 72 : end subroutine compute_resolvent_column_shift_lanczos
397 : !!***
398 :
399 :
400 : !!****f* m_hamiltonian/compute_resolvent_column_shift_lanczos_right_vectors
401 : !! NAME
402 : !! compute_resolvent_column_shift_lanczos_right_vectors
403 : !!
404 : !! FUNCTION
405 : !! .
406 : !!
407 : !! INPUTS
408 : !!
409 : !! OUTPUT
410 : !!
411 : !! SOURCE
412 :
413 72 : subroutine compute_resolvent_column_shift_lanczos_right_vectors(seed_vector, right_vec)
414 : !----------------------------------------------------------------------------------------------------
415 : ! The goal of this routine is to participate in the computation of a column of the resolvent
416 : ! using the shift lanczos algorithm. This routine should be called FIRST.
417 : !
418 : ! This routine:
419 : !
420 : ! 1) builds the preconditioned Hamiltonian Lanczos basis, using the seed_vector, and
421 : ! stores result in the Module variables.
422 : !
423 : ! 2) prepares and returns the Lanczos basis-projected right vectors, ready for further processing.
424 : !
425 : !
426 : !----------------------------------------------------------------------------------------------------
427 : implicit none
428 :
429 : complex(dp), intent(in) :: seed_vector(npw_g)
430 : complex(dp), intent(out):: right_vec(LR_kmax)
431 :
432 : ! local variables
433 : integer :: mpi_communicator
434 : integer :: ierr
435 :
436 144 : complex(dp) :: work_array(npw_g)
437 :
438 : ! *************************************************************************
439 :
440 :
441 : ! processes will communicate along FFT rows
442 72 : mpi_communicator = mpi_enreg%comm_fft
443 :
444 : !----------------------------------------------------------------------------------------------------
445 : ! First, build the Lanczos basis for the preconditioned Hamiltonian
446 : !----------------------------------------------------------------------------------------------------
447 72 : call build_preconditioned_Hamiltonian_Lanczos_basis(seed_vector)
448 :
449 : !----------------------------------------------------------------------------------------------------
450 : ! Next, generate arrays which do not depend on z, the external shift.
451 : !----------------------------------------------------------------------------------------------------
452 :
453 : ! Q^dagger . C^{-2} | seed >
454 14464 : work_array(:) = precondition_one_on_C(:)**2*seed_vector(:)
455 :
456 72 : call ZGEMV('C', npw_g, LR_kmax, cmplx_1, Hamiltonian_Qk, npw_g, work_array, 1, cmplx_0, right_vec, 1)
457 72 : call xmpi_sum(right_vec,mpi_communicator,ierr) ! sum on all processors working on FFT!
458 :
459 :
460 72 : end subroutine compute_resolvent_column_shift_lanczos_right_vectors
461 : !!***
462 :
463 :
464 :
465 : !!****f* m_hamiltonian/invert_general_matrix
466 : !! NAME
467 : !! invert_general_matrix
468 : !!
469 : !! FUNCTION
470 : !! .
471 : !!
472 : !! INPUTS
473 : !!
474 : !! OUTPUT
475 : !!
476 : !! SOURCE
477 :
478 2152 : subroutine invert_general_matrix(n,matrix)
479 : !----------------------------------------------------------------------------------------------------
480 : ! Simple wrapper around lapack routines to invert a general matrix
481 : !----------------------------------------------------------------------------------------------------
482 : implicit none
483 :
484 : integer, intent(in) :: n
485 : complex(dp), intent(inout) :: matrix(n,n)
486 :
487 : integer :: info
488 4304 : integer :: ipiv(n)
489 :
490 : integer :: debug_unit
491 : character(50) :: debug_filename
492 4304 : complex(dp) :: work(n)
493 :
494 : ! *************************************************************************
495 :
496 2152 : call ZGETRF( n, n, matrix, n, ipiv, info )
497 2152 : if ( info /= 0) then
498 0 : debug_unit = get_unit()
499 0 : write(debug_filename,'(A,I4.4,A)') 'LAPACK_DEBUG_PROC=',mpi_enreg%me,'.log'
500 :
501 0 : open(debug_unit,file=trim(debug_filename),status='unknown')
502 :
503 0 : write(debug_unit,'(A)') '*********************************************************************************************'
504 0 : write(debug_unit,'(A,I4,A)') '* ERROR: info = ',info,' in ZGETRF(1), gwls_LanczosResolvents'
505 0 : write(debug_unit,'(A)') '*********************************************************************************************'
506 :
507 0 : close(debug_unit)
508 :
509 : end if
510 :
511 :
512 2152 : call ZGETRI( n, matrix, n, ipiv, work, n, info )
513 :
514 2152 : if ( info /= 0) then
515 0 : debug_unit = get_unit()
516 0 : write(debug_filename,'(A,I4.4,A)') 'LAPACK_DEBUG_PROC=',mpi_enreg%me,'.log'
517 :
518 0 : open(debug_unit,file=trim(debug_filename),status='unknown')
519 :
520 0 : write(debug_unit,'(A)') '*********************************************************************************************'
521 0 : write(debug_unit,'(A,I4,A)') '* ERROR: info = ',info,' in ZGETRI(1), gwls_LanczosResolvents'
522 0 : write(debug_unit,'(A)') '*********************************************************************************************'
523 :
524 0 : close(debug_unit)
525 :
526 : end if
527 :
528 :
529 2152 : end subroutine invert_general_matrix
530 : !!***
531 :
532 :
533 : end module m_gwls_LanczosResolvents
534 : !!***
|