Line data Source code
1 : !!****m* ABINIT/m_gwls_Projected_BT
2 : !! NAME
3 : !! m_gwls_Projected_BT
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_Projected_BT
24 : !----------------------------------------------------------------------------------------------------
25 : ! This module contains routines to compute the projections of the Sternheimer equations for the
26 : ! BT operator, which appears in the Numerical integral.
27 : !----------------------------------------------------------------------------------------------------
28 : ! local modules
29 : use m_gwls_utility
30 : use m_gwls_wf
31 : use m_gwls_TimingLog
32 : use m_gwls_hamiltonian
33 : use m_gwls_lineqsolver
34 : use m_gwls_GWlanczos
35 : use m_gwls_LanczosBasis
36 : use m_gwls_DielectricArray
37 : use m_gwls_LanczosResolvents
38 : ! abinit modules
39 : use defs_basis
40 : use m_abicore
41 : use m_xmpi
42 :
43 : implicit none
44 : save
45 : private
46 : !!***
47 :
48 : ! Module arrays, to be set and used in this module
49 : integer, public :: BT_lsternheimer
50 : complex(dp), public, allocatable :: projected_BT_A_matrix(:,:)
51 : complex(dp), public, allocatable :: projected_BT_L_matrix(:,:)
52 : complex(dp), public, allocatable :: projected_BT_BETA_matrix(:,:)
53 :
54 : integer, public :: BT_lsternheimer_Lanczos
55 : ! We use pointers so that arrays may be allocated in a subroutine
56 : complex(dp), public, pointer:: projected_BT_A_matrix_Lanczos(:,:)
57 : complex(dp), public, pointer:: projected_BT_L_matrix_Lanczos(:,:)
58 : complex(dp), public, pointer:: projected_BT_BETA_matrix_Lanczos(:,:)
59 :
60 :
61 : integer, public :: BT_lsternheimer_model_Lanczos
62 : ! We use pointers so that arrays may be allocated in a subroutine
63 : complex(dp), public, pointer :: projected_BT_A_matrix_model_Lanczos(:,:)
64 : complex(dp), public, pointer :: projected_BT_L_matrix_model_Lanczos(:,:)
65 : complex(dp), public, pointer :: projected_BT_BETA_matrix_model_Lanczos(:,:)
66 : !!***
67 :
68 :
69 : ! Public methods
70 : public :: compute_projected_BT_shift_Lanczos
71 : public :: compute_projected_BT_shift_Lanczos_DISTRIBUTED
72 : !!***
73 : contains
74 :
75 : !!****f* m_hamiltonian/compute_projected_BT_shift_Lanczos
76 : !! NAME
77 : !! compute_projected_BT_shift_Lanczos
78 : !!
79 : !! FUNCTION
80 : !! .
81 : !!
82 : !! INPUTS
83 : !!
84 : !! OUTPUT
85 : !!
86 : !! SOURCE
87 :
88 7 : subroutine compute_projected_BT_shift_Lanczos(nfreq, list_external_omega, lmax, modified_Lbasis, &
89 7 : kmax_numeric, npt_gauss, dielectric_array, array_integrand )
90 : !----------------------------------------------------------------------------------------------------
91 : !
92 : ! This function returns the integrand
93 : !
94 : ! I(w', w) = sum_{l1,l2} DielectricArray_{l1,l2}(w') * B_{l1,l2}(w',w)
95 : !
96 : ! where BT is obtained by Shift Lanczos for all frequencies. It is assumed that modified_Lbasis
97 : ! already contains the properly modified basis vectors.
98 : !
99 : !----------------------------------------------------------------------------------------------------
100 : integer, intent(in) :: nfreq
101 : real(dp), intent(in) :: list_external_omega(nfreq)
102 : integer, intent(in) :: lmax
103 : integer, intent(in) :: kmax_numeric
104 : integer, intent(in) :: npt_gauss
105 : complex(dp), intent(in) :: modified_Lbasis(npw_k,lmax)
106 : complex(dp), intent(in) :: dielectric_array(lmax,lmax,npt_gauss+1)
107 : complex(dp), intent(out):: array_integrand(npt_gauss+1,nfreq)
108 :
109 :
110 : ! local variables
111 :
112 : logical :: prec
113 :
114 : integer :: l, l1, iw_ext, iw_prime, iw, mb, iblk, nbdblock_lanczos
115 : integer :: ierr
116 :
117 : integer :: mpi_band_rank
118 :
119 : integer :: k
120 : integer :: iz, nz
121 : complex(dp) :: z
122 :
123 7 : complex(dp), allocatable :: list_z(:)
124 :
125 : real(dp) :: external_omega, omega_prime
126 :
127 :
128 7 : complex(dp), allocatable :: matrix_elements_resolvent(:,:)
129 :
130 7 : real(dp), allocatable :: psik_wrk(:,:)
131 7 : real(dp), allocatable :: psikb_wrk(:,:)
132 7 : real(dp), allocatable :: psikg_wrk(:,:)
133 :
134 7 : complex(dp), allocatable :: seed_vector(:)
135 :
136 7 : complex(dp), allocatable :: right_vec_FFT(:)
137 :
138 7 : complex(dp), allocatable :: right_vec_LA(:,:)
139 7 : complex(dp), allocatable :: LR_M_matrix_LA(:,:,:)
140 7 : complex(dp), allocatable :: Hamiltonian_Qk_LA(:,:,:)
141 : complex(dp), allocatable :: left_vecs_LA(:,:)
142 7 : complex(dp), allocatable :: shift_lanczos_matrix(:,:)
143 :
144 7 : complex(dp), allocatable :: work_vec(:)
145 :
146 :
147 : real(dp), allocatable :: real_wrk_vec(:), imag_wrk_vec(:)
148 : real(dp), allocatable :: real_wrk_mat(:,:), imag_wrk_mat(:,:)
149 :
150 : ! *************************************************************************
151 :
152 : ! prepare the complex frequency array
153 7 : nz = 2*nfreq*npt_gauss
154 21 : ABI_MALLOC(list_z,(nz))
155 :
156 28 : ABI_MALLOC(matrix_elements_resolvent, (lmax,nz))
157 :
158 21 : ABI_MALLOC(psik_wrk, (2,npw_k))
159 21 : ABI_MALLOC(psikb_wrk, (2,npw_kb))
160 21 : ABI_MALLOC(psikg_wrk, (2,npw_g))
161 21 : ABI_MALLOC(seed_vector, (npw_g))
162 :
163 :
164 21 : ABI_MALLOC(real_wrk_vec, (kmax_numeric*blocksize))
165 14 : ABI_MALLOC(imag_wrk_vec, (kmax_numeric*blocksize))
166 28 : ABI_MALLOC(real_wrk_mat, (kmax_numeric,kmax_numeric*blocksize))
167 21 : ABI_MALLOC(imag_wrk_mat, (kmax_numeric,kmax_numeric*blocksize))
168 :
169 28 : ABI_MALLOC(shift_lanczos_matrix, (kmax_numeric,kmax_numeric))
170 :
171 21 : ABI_MALLOC(work_vec, (kmax_numeric))
172 :
173 14 : ABI_MALLOC(right_vec_FFT,(kmax_numeric) )
174 28 : ABI_MALLOC(right_vec_LA,(kmax_numeric, blocksize) )
175 35 : ABI_MALLOC(LR_M_matrix_LA,(kmax_numeric,kmax_numeric, blocksize) )
176 35 : ABI_MALLOC(Hamiltonian_Qk_LA,(npw_k, kmax_numeric, blocksize) )
177 :
178 :
179 28 : ABI_MALLOC(left_vecs_LA,(kmax_numeric, lmax) )
180 :
181 7 : iw = 0
182 14 : do iw_ext = 1, nfreq
183 :
184 7 : external_omega = list_external_omega(iw_ext)
185 :
186 84 : do iw_prime = 1, npt_gauss
187 :
188 : ! Remember! the first element of the list_omega array, which contain the imaginary
189 : ! integration frequencies, is zero (which need not be computed explicitly)
190 :
191 70 : omega_prime = list_omega(iw_prime+1)
192 :
193 70 : iw = iw+1
194 70 : list_z(iw) = cmplx_1*external_omega-cmplx_i*omega_prime
195 :
196 70 : iw = iw+1
197 77 : list_z(iw) = cmplx_1*external_omega+cmplx_i*omega_prime
198 :
199 : end do
200 :
201 : end do
202 :
203 :
204 : ! initialize the array to zero
205 91 : array_integrand(:,:) = cmplx_0
206 :
207 :
208 : ! prepare the shift lanczos scheme
209 7 : prec = .false. ! let's not precondition for now
210 7 : call setup_LanczosResolvents(kmax_numeric,prec)
211 :
212 : ! Number of blocks of lanczos vectors
213 7 : nbdblock_lanczos = lmax/blocksize
214 7 : if (modulo(lmax,blocksize) /= 0) nbdblock_lanczos = nbdblock_lanczos + 1
215 :
216 7 : mpi_band_rank = mpi_enreg%me_band
217 :
218 :
219 :
220 : !-------------------------------------------------------------------
221 : !
222 : ! The shift lanczos scheme will be implemented explicitly in the
223 : ! loop below instead of being wrapped in routines in the module
224 : ! gwls_LanczosResolvents. The task to be performed is subtle
225 : ! because of the different data distributions and the need to
226 : ! project on all Lanczos vectors.
227 : !
228 : !-------------------------------------------------------------------
229 :
230 : ! loop on all blocks of Lanczos vectors
231 47 : do iblk = 1, nbdblock_lanczos
232 :
233 : ! Convert a block of Lanczos vectors to the FFT configuration
234 :
235 : ! Change the configuration of the data
236 96 : do mb =1, blocksize
237 56 : l = (iblk-1)*blocksize+mb
238 56 : if (l <= lmax) then
239 8280 : psik_wrk(1,:) = dble ( modified_Lbasis(:,l) )
240 8280 : psik_wrk(2,:) = dimag( modified_Lbasis(:,l) )
241 : else
242 0 : psik_wrk(:,:) = zero
243 : end if
244 :
245 24768 : psikb_wrk(:,(mb-1)*npw_k+1:mb*npw_k) = psik_wrk(:,:)
246 :
247 : end do ! mb
248 :
249 : ! change configuration of the data, from LA to FFT
250 40 : call wf_block_distribute(psikb_wrk, psikg_wrk, 1) ! LA -> FFT
251 :
252 : ! compute the seed vector for this block
253 8264 : seed_vector(:) = cmplx_1*psikg_wrk(1,:) + cmplx_i*psikg_wrk(2,:)
254 :
255 :
256 : ! Compute the Lanczos basis for the Hamiltonian, in FFT configuration,
257 : ! given the seed vector. Project the right vector onto the thus produced Lanczos basis.
258 40 : call compute_resolvent_column_shift_lanczos_right_vectors(seed_vector, right_vec_FFT)
259 :
260 : ! Distribute the data from the FFT configuration back to the LA configuration
261 : ! We will use some public data from the LanczosResolvent module.
262 : !
263 : ! PATTERN: xmpi_allgather(xval,nelem,recvbuf,spaceComm,ier)
264 : ! unfortunately, there are only interfaces for real arguments, not complex.
265 :
266 680 : call xmpi_allgather( dble(right_vec_FFT), kmax_numeric, real_wrk_vec, mpi_enreg%comm_band, ierr)
267 680 : call xmpi_allgather(dimag(right_vec_FFT), kmax_numeric, imag_wrk_vec, mpi_enreg%comm_band, ierr)
268 :
269 :
270 :
271 10920 : call xmpi_allgather( dble(LR_M_matrix), kmax_numeric**2, real_wrk_mat, mpi_enreg%comm_band, ierr)
272 10920 : call xmpi_allgather(dimag(LR_M_matrix), kmax_numeric**2, imag_wrk_mat, mpi_enreg%comm_band, ierr)
273 :
274 :
275 96 : do mb =1, blocksize
276 : right_vec_LA (:,mb) = cmplx_1*real_wrk_vec((mb-1)*kmax_numeric+1:mb*kmax_numeric) + &
277 952 : & cmplx_i*imag_wrk_vec((mb-1)*kmax_numeric+1:mb*kmax_numeric)
278 :
279 :
280 : LR_M_matrix_LA(:,:,mb) = cmplx_1*real_wrk_mat(:,(mb-1)*kmax_numeric+1:mb*kmax_numeric) + &
281 15328 : & cmplx_i*imag_wrk_mat(:,(mb-1)*kmax_numeric+1:mb*kmax_numeric)
282 : end do ! mb
283 :
284 680 : do k = 1, kmax_numeric
285 :
286 132224 : psikg_wrk(1,:) = dble ( Hamiltonian_Qk(:,k) )
287 132224 : psikg_wrk(2,:) = dimag( Hamiltonian_Qk(:,k) )
288 :
289 : ! change configuration of the data, from FFT to LA
290 640 : call wf_block_distribute(psikb_wrk, psikg_wrk, 2) ! FFT -> LA
291 :
292 1576 : do mb=1, blocksize
293 :
294 : Hamiltonian_Qk_LA(:, k, mb) = cmplx_1*psikb_wrk(1,(mb-1)*npw_k+1:mb*npw_k) &
295 133120 : & +cmplx_i*psikb_wrk(2,(mb-1)*npw_k+1:mb*npw_k)
296 :
297 : end do ! mb
298 :
299 : end do ! k
300 :
301 :
302 : ! Data is now available in LA configuration, perfect for linear algebra!
303 :
304 :
305 103 : do mb = 1, blocksize
306 : ! loop on all vectors in this block
307 :
308 56 : l1 = (iblk-1)*blocksize+mb
309 :
310 56 : if (l1 > lmax) cycle
311 :
312 : ! Compute Q^dagger | left_vectors >
313 :
314 : ! computes C = alpha * op(A).op(B) + beta * C
315 : call ZGEMM( 'C', & ! First array is hermitian conjugated
316 : 'N', & ! second array is taken as is
317 : kmax_numeric, & ! number of rows of matrix op(A)
318 : lmax, & ! number of columns of matrix op(B)
319 : npw_k, & ! number of columns of op(A) == number of rows of matrix op(B)
320 : cmplx_1, & ! alpha
321 : Hamiltonian_Qk_LA(:, :, mb), & ! A matrix
322 : npw_k, & ! LDA
323 : modified_Lbasis, & ! B matrix
324 : npw_k, & ! LDB
325 : cmplx_0, & ! beta
326 : left_vecs_LA, & ! C matrix
327 56 : kmax_numeric) ! LDC
328 :
329 56 : call xmpi_sum(left_vecs_LA,mpi_enreg%comm_bandfft,ierr) ! sum on all processors working on LA
330 :
331 : ! Use shift Lanczos to compute all matrix elements!
332 :
333 : ! THE FOLLOWING COULD BE DONE IN PARALLEL INSTEAD OF HAVING EVERY PROCESSOR DUMBLY DO THE SAME THING
334 1176 : do iz = 1, nz
335 :
336 1120 : z = list_z(iz)
337 :
338 : ! Generate the matrix to be inverted
339 305760 : shift_lanczos_matrix(:,:) = LR_M_matrix_LA(:,:,mb)
340 :
341 19040 : do k = 1, kmax_numeric
342 19040 : shift_lanczos_matrix(k,k) = shift_lanczos_matrix(k,k)-z
343 : end do
344 :
345 : ! since z could be complex, the matrix is not necessarily hermitian. Invert using general Lapack scheme
346 1120 : call invert_general_matrix(kmax_numeric,shift_lanczos_matrix)
347 : ! the matrix now contains the inverse!
348 :
349 :
350 : ! | work_vec > = M^{-1} . | right_vec >
351 :
352 : ! compute y = alpha op(A).x + beta y
353 :
354 : call ZGEMV( 'N', &! A matrix is as is
355 : kmax_numeric, &! number of rows of matrix A
356 : kmax_numeric, &! number of columns of matrix A
357 : cmplx_1, &! alpha
358 : shift_lanczos_matrix, &! matrix A
359 : kmax_numeric, &! LDA
360 : right_vec_LA(:,mb), &! array X
361 : 1, &! INC X
362 : cmplx_0, &! beta
363 : work_vec, &! Y array
364 1120 : 1) ! INC Y
365 :
366 :
367 : ! matrix_elements = < right_vecs | work_vec >
368 :
369 : call ZGEMV( 'C', &! A matrix is hermitan conjugate
370 : kmax_numeric, &! number of rows of matrix A
371 : lmax, &! number of columns of matrix A
372 : cmplx_1, &! alpha
373 : left_vecs_LA, &! matrix A
374 : kmax_numeric, &! LDA
375 : work_vec, &! array X
376 : 1, &! INC X
377 : cmplx_0, &! beta
378 : matrix_elements_resolvent(:,iz), &! Y array
379 1176 : 1) ! INC Y
380 :
381 :
382 :
383 : end do ! iz
384 :
385 : ! update integrand
386 : iw = 0
387 208 : do iw_ext = 1, nfreq
388 672 : do iw_prime = 1, npt_gauss
389 :
390 560 : iw = iw+1
391 :
392 : ! this expression will be normalized by 1/2pi at the end
393 : array_integrand(iw_prime+1,iw_ext) = array_integrand(iw_prime+1,iw_ext) + &
394 : sum(dielectric_array(:,l1,iw_prime+1)* &
395 5040 : (matrix_elements_resolvent(:,iw)+matrix_elements_resolvent(:,iw+1)))
396 :
397 616 : iw = iw+1
398 :
399 : end do !iw_prime
400 : end do !iw_ext
401 :
402 :
403 :
404 : end do !mb
405 : end do ! iblk
406 :
407 : ! normalize !
408 91 : array_integrand(:,:) = array_integrand(:,:)/(2.0_dp*pi)
409 :
410 :
411 :
412 7 : call cleanup_LanczosResolvents
413 :
414 :
415 7 : ABI_FREE(psik_wrk)
416 7 : ABI_FREE(psikb_wrk)
417 7 : ABI_FREE(psikg_wrk)
418 :
419 7 : ABI_FREE(seed_vector)
420 7 : ABI_FREE(work_vec)
421 :
422 :
423 7 : ABI_FREE(right_vec_FFT)
424 7 : ABI_FREE(right_vec_LA)
425 :
426 7 : ABI_FREE(LR_M_matrix_LA)
427 :
428 7 : ABI_FREE(Hamiltonian_Qk_LA)
429 :
430 7 : ABI_FREE(real_wrk_vec)
431 7 : ABI_FREE(imag_wrk_vec)
432 7 : ABI_FREE(real_wrk_mat)
433 7 : ABI_FREE(imag_wrk_mat)
434 :
435 :
436 7 : ABI_FREE(shift_lanczos_matrix)
437 7 : ABI_FREE(left_vecs_LA)
438 :
439 :
440 7 : ABI_FREE(list_z)
441 7 : ABI_FREE(matrix_elements_resolvent)
442 :
443 7 : end subroutine compute_projected_BT_shift_Lanczos
444 : !!***
445 :
446 :
447 :
448 : !!****f* m_hamiltonian/compute_projected_BT_shift_Lanczos_DISTRIBUTED
449 : !! NAME
450 : !! compute_projected_BT_shift_Lanczos_DISTRIBUTED
451 : !!
452 : !! FUNCTION
453 : !! .
454 : !!
455 : !! INPUTS
456 : !!
457 : !! OUTPUT
458 : !!
459 : !! SOURCE
460 :
461 6 : subroutine compute_projected_BT_shift_Lanczos_DISTRIBUTED(nfreq, list_external_omega, lmax,blocksize_eps, &
462 6 : model_lanczos_vector_belongs_to_this_node, model_lanczos_vector_index, &
463 6 : modified_Lbasis, kmax_numeric, npt_gauss, dielectric_array, array_integrand )
464 : !----------------------------------------------------------------------------------------------------
465 : !
466 : ! This function returns the integrand
467 : !
468 : ! I(w', w) = sum_{l1,l2} DielectricArray_{l1,l2}(w') * B_{l1,l2}(w',w)
469 : !
470 : ! where BT is obtained by shift Lanczos for all frequencies. It is assumed that modified_Lbasis
471 : ! already contains the properly modified basis vectors.
472 : !
473 : ! This routine performs the same function as compute_projected_BT_shift_Lanczos, but
474 : ! takes into account that the MODEL dielectric array is distributed over the processors.
475 : !
476 : !----------------------------------------------------------------------------------------------------
477 : integer, intent(in) :: nfreq
478 : real(dp), intent(in) :: list_external_omega(nfreq)
479 : integer, intent(in) :: lmax, blocksize_eps
480 : integer, intent(in) :: kmax_numeric
481 : integer, intent(in) :: npt_gauss
482 : complex(dp), intent(in) :: modified_Lbasis(npw_k,lmax)
483 : complex(dp), intent(in) :: dielectric_array(lmax, blocksize_eps, npt_gauss+1)
484 :
485 : logical, intent(in) :: model_lanczos_vector_belongs_to_this_node(lmax)
486 : integer, intent(in) :: model_lanczos_vector_index(lmax)
487 :
488 : complex(dp), intent(out):: array_integrand(npt_gauss+1,nfreq)
489 :
490 :
491 :
492 : ! local variables
493 :
494 : logical :: prec
495 :
496 : integer :: l, l1, lb, iw_ext, iw_prime, iw, mb, iblk, nbdblock_lanczos
497 : integer :: ierr
498 :
499 : integer :: mpi_band_rank
500 :
501 : integer :: k
502 : integer :: iz, nz
503 : complex(dp) :: z
504 :
505 6 : complex(dp), allocatable :: list_z(:)
506 :
507 : real(dp) :: external_omega, omega_prime
508 :
509 :
510 6 : complex(dp), allocatable :: matrix_elements_resolvent(:,:)
511 :
512 6 : real(dp), allocatable :: psik_wrk(:,:)
513 6 : real(dp), allocatable :: psikb_wrk(:,:)
514 6 : real(dp), allocatable :: psikg_wrk(:,:)
515 :
516 6 : complex(dp), allocatable :: seed_vector(:)
517 6 : complex(dp), allocatable :: right_vec_FFT(:)
518 6 : complex(dp), allocatable :: right_vec_LA(:,:)
519 6 : complex(dp), allocatable :: LR_M_matrix_LA(:,:,:)
520 6 : complex(dp), allocatable :: Hamiltonian_Qk_LA(:,:,:)
521 : complex(dp), allocatable :: left_vecs_LA(:,:)
522 6 : complex(dp), allocatable :: shift_lanczos_matrix(:,:)
523 6 : complex(dp), allocatable :: work_vec(:)
524 :
525 :
526 : real(dp), allocatable :: real_wrk_vec(:), imag_wrk_vec(:)
527 : real(dp), allocatable :: real_wrk_mat(:,:), imag_wrk_mat(:,:)
528 :
529 : ! *************************************************************************
530 :
531 : ! prepare the complex frequency array
532 6 : nz = 2*nfreq*npt_gauss
533 18 : ABI_MALLOC(list_z,(nz))
534 :
535 24 : ABI_MALLOC(matrix_elements_resolvent, (lmax,nz))
536 :
537 18 : ABI_MALLOC(psik_wrk, (2,npw_k))
538 18 : ABI_MALLOC(psikb_wrk, (2,npw_kb))
539 18 : ABI_MALLOC(psikg_wrk, (2,npw_g))
540 18 : ABI_MALLOC(seed_vector, (npw_g))
541 :
542 :
543 18 : ABI_MALLOC(real_wrk_vec, (kmax_numeric*blocksize))
544 12 : ABI_MALLOC(imag_wrk_vec, (kmax_numeric*blocksize))
545 24 : ABI_MALLOC(real_wrk_mat, (kmax_numeric,kmax_numeric*blocksize))
546 18 : ABI_MALLOC(imag_wrk_mat, (kmax_numeric,kmax_numeric*blocksize))
547 :
548 24 : ABI_MALLOC(shift_lanczos_matrix, (kmax_numeric,kmax_numeric))
549 :
550 18 : ABI_MALLOC(work_vec, (kmax_numeric))
551 :
552 12 : ABI_MALLOC(right_vec_FFT,(kmax_numeric) )
553 24 : ABI_MALLOC(right_vec_LA,(kmax_numeric, blocksize) )
554 30 : ABI_MALLOC(LR_M_matrix_LA,(kmax_numeric,kmax_numeric, blocksize) )
555 30 : ABI_MALLOC(Hamiltonian_Qk_LA,(npw_k, kmax_numeric, blocksize) )
556 :
557 :
558 24 : ABI_MALLOC(left_vecs_LA,(kmax_numeric, lmax) )
559 :
560 6 : iw = 0
561 12 : do iw_ext = 1, nfreq
562 :
563 6 : external_omega = list_external_omega(iw_ext)
564 :
565 72 : do iw_prime = 1, npt_gauss
566 :
567 : ! Remember! the first element of the list_omega array, which contain the imaginary
568 : ! integration frequencies, is zero (which need not be computed explicitly)
569 :
570 60 : omega_prime = list_omega(iw_prime+1)
571 :
572 60 : iw = iw+1
573 60 : list_z(iw) = cmplx_1*external_omega-cmplx_i*omega_prime
574 :
575 60 : iw = iw+1
576 66 : list_z(iw) = cmplx_1*external_omega+cmplx_i*omega_prime
577 :
578 : end do
579 :
580 : end do
581 :
582 :
583 : ! initialize the array to zero
584 78 : array_integrand(:,:) = cmplx_0
585 :
586 :
587 : ! prepare the shift lanczos scheme
588 6 : prec = .false. ! let's not precondition for now
589 6 : call setup_LanczosResolvents(kmax_numeric,prec)
590 :
591 : ! Number of blocks of lanczos vectors
592 6 : nbdblock_lanczos = lmax/blocksize
593 6 : if (modulo(lmax,blocksize) /= 0) nbdblock_lanczos = nbdblock_lanczos + 1
594 :
595 6 : mpi_band_rank = mpi_enreg%me_band
596 :
597 :
598 :
599 : !-------------------------------------------------------------------
600 : !
601 : ! The shift lanczos scheme will be implemented explicitly in the
602 : ! loop below instead of being wrapped in routines in the module
603 : ! gwls_LanczosResolvents. The task to be performed is subtle
604 : ! because of the different data distributions and the need to
605 : ! project on all Lanczos vectors.
606 : !
607 : !-------------------------------------------------------------------
608 :
609 : ! loop on all blocks of Lanczos vectors
610 38 : do iblk = 1, nbdblock_lanczos
611 :
612 : ! Convert a block of Lanczos vectors to the FFT configuration
613 :
614 : ! Change the configuration of the data
615 80 : do mb =1, blocksize
616 48 : l = (iblk-1)*blocksize+mb
617 48 : if (l <= lmax) then
618 6216 : psik_wrk(1,:) = dble ( modified_Lbasis(:,l) )
619 6216 : psik_wrk(2,:) = dimag( modified_Lbasis(:,l) )
620 : else
621 0 : psik_wrk(:,:) = zero
622 : end if
623 :
624 18584 : psikb_wrk(:,(mb-1)*npw_k+1:mb*npw_k) = psik_wrk(:,:)
625 :
626 : end do ! mb
627 :
628 : ! change configuration of the data, from LA to FFT
629 32 : call wf_block_distribute(psikb_wrk, psikg_wrk, 1) ! LA -> FFT
630 :
631 : ! compute the seed vector for this block
632 6200 : seed_vector(:) = cmplx_1*psikg_wrk(1,:) + cmplx_i*psikg_wrk(2,:)
633 :
634 :
635 : ! Compute the Lanczos basis for the Hamiltonian, in FFT configuration,
636 : ! given the seed vector. Project the right vector onto the thus produced Lanczos basis.
637 32 : call compute_resolvent_column_shift_lanczos_right_vectors(seed_vector, right_vec_FFT)
638 :
639 : ! Distribute the data from the FFT configuration back to the LA configuration
640 : ! We will use some public data from the LanczosResolvent module.
641 : !
642 : ! PATTERN: xmpi_allgather(xval,nelem,recvbuf,spaceComm,ier)
643 : ! unfortunately, there are only interfaces for real arguments, not complex.
644 :
645 544 : call xmpi_allgather( dble(right_vec_FFT), kmax_numeric, real_wrk_vec, mpi_enreg%comm_band, ierr)
646 544 : call xmpi_allgather(dimag(right_vec_FFT), kmax_numeric, imag_wrk_vec, mpi_enreg%comm_band, ierr)
647 :
648 :
649 :
650 8736 : call xmpi_allgather( dble(LR_M_matrix), kmax_numeric**2, real_wrk_mat, mpi_enreg%comm_band, ierr)
651 8736 : call xmpi_allgather(dimag(LR_M_matrix), kmax_numeric**2, imag_wrk_mat, mpi_enreg%comm_band, ierr)
652 :
653 :
654 80 : do mb =1, blocksize
655 : right_vec_LA (:,mb) = cmplx_1*real_wrk_vec((mb-1)*kmax_numeric+1:mb*kmax_numeric) + &
656 816 : & cmplx_i*imag_wrk_vec((mb-1)*kmax_numeric+1:mb*kmax_numeric)
657 :
658 :
659 : LR_M_matrix_LA(:,:,mb) = cmplx_1*real_wrk_mat(:,(mb-1)*kmax_numeric+1:mb*kmax_numeric) + &
660 13136 : & cmplx_i*imag_wrk_mat(:,(mb-1)*kmax_numeric+1:mb*kmax_numeric)
661 : end do ! mb
662 :
663 544 : do k = 1, kmax_numeric
664 :
665 99200 : psikg_wrk(1,:) = dble ( Hamiltonian_Qk(:,k) )
666 99200 : psikg_wrk(2,:) = dimag( Hamiltonian_Qk(:,k) )
667 :
668 : ! change configuration of the data, from FFT to LA
669 512 : call wf_block_distribute(psikb_wrk, psikg_wrk, 2) ! FFT -> LA
670 :
671 1312 : do mb=1, blocksize
672 :
673 : Hamiltonian_Qk_LA(:, k, mb) = cmplx_1*psikb_wrk(1,(mb-1)*npw_k+1:mb*npw_k) &
674 99968 : & +cmplx_i*psikb_wrk(2,(mb-1)*npw_k+1:mb*npw_k)
675 :
676 : end do ! mb
677 :
678 : end do ! k
679 :
680 :
681 : ! Data is now available in LA configuration, perfect for linear algebra!
682 :
683 :
684 86 : do mb = 1, blocksize
685 : ! loop on all vectors in this block
686 :
687 48 : l1 = (iblk-1)*blocksize+mb
688 :
689 48 : if (l1 > lmax) cycle
690 :
691 : ! Compute Q^dagger | left_vectors >
692 :
693 : ! computes C = alpha * op(A).op(B) + beta * C
694 : call ZGEMM( 'C', & ! First array is hermitian conjugated
695 : 'N', & ! second array is taken as is
696 : kmax_numeric, & ! number of rows of matrix op(A)
697 : lmax, & ! number of columns of matrix op(B)
698 : npw_k, & ! number of columns of op(A) == number of rows of matrix op(B)
699 : cmplx_1, & ! alpha
700 : Hamiltonian_Qk_LA(:, :, mb), & ! A matrix
701 : npw_k, & ! LDA
702 : modified_Lbasis, & ! B matrix
703 : npw_k, & ! LDB
704 : cmplx_0, & ! beta
705 : left_vecs_LA, & ! C matrix
706 48 : kmax_numeric) ! LDC
707 :
708 48 : call xmpi_sum(left_vecs_LA,mpi_enreg%comm_bandfft,ierr) ! sum on all processors working on LA
709 :
710 : ! Use shift Lanczos to compute all matrix elements!
711 :
712 : ! THE FOLLOWING COULD BE DONE IN PARALLEL INSTEAD OF HAVING EVERY PROCESSOR DUMBLY DO THE SAME THING
713 1008 : do iz = 1, nz
714 :
715 960 : z = list_z(iz)
716 :
717 : ! Generate the matrix to be inverted
718 262080 : shift_lanczos_matrix(:,:) = LR_M_matrix_LA(:,:,mb)
719 :
720 16320 : do k = 1, kmax_numeric
721 16320 : shift_lanczos_matrix(k,k) = shift_lanczos_matrix(k,k)-z
722 : end do
723 :
724 : ! since z could be complex, the matrix is not necessarily hermitian. Invert using general Lapack scheme
725 960 : call invert_general_matrix(kmax_numeric,shift_lanczos_matrix)
726 : ! the matrix now contains the inverse!
727 :
728 :
729 : ! | work_vec > = M^{-1} . | right_vec >
730 :
731 : ! compute y = alpha op(A).x + beta y
732 :
733 : call ZGEMV( 'N', &! A matrix is as is
734 : kmax_numeric, &! number of rows of matrix A
735 : kmax_numeric, &! number of columns of matrix A
736 : cmplx_1, &! alpha
737 : shift_lanczos_matrix, &! matrix A
738 : kmax_numeric, &! LDA
739 : right_vec_LA(:,mb), &! array X
740 : 1, &! INC X
741 : cmplx_0, &! beta
742 : work_vec, &! Y array
743 960 : 1) ! INC Y
744 :
745 :
746 : ! matrix_elements = < right_vecs | work_vec >
747 :
748 : call ZGEMV( 'C', &! A matrix is hermitan conjugate
749 : kmax_numeric, &! number of rows of matrix A
750 : lmax, &! number of columns of matrix A
751 : cmplx_1, &! alpha
752 : left_vecs_LA, &! matrix A
753 : kmax_numeric, &! LDA
754 : work_vec, &! array X
755 : 1, &! INC X
756 : cmplx_0, &! beta
757 : matrix_elements_resolvent(:,iz), &! Y array
758 1008 : 1) ! INC Y
759 :
760 :
761 :
762 : end do ! iz
763 :
764 128 : if ( model_lanczos_vector_belongs_to_this_node(l1) ) then
765 :
766 24 : lb = model_lanczos_vector_index(l1)
767 :
768 :
769 :
770 : ! update integrand
771 24 : iw = 0
772 48 : do iw_ext = 1, nfreq
773 288 : do iw_prime = 1, npt_gauss
774 :
775 240 : iw = iw+1
776 :
777 : ! this expression will be normalized by 1/2pi at the end
778 : array_integrand(iw_prime+1,iw_ext) = array_integrand(iw_prime+1,iw_ext) + &
779 : sum(dielectric_array(:,lb,iw_prime+1)* &
780 2160 : (matrix_elements_resolvent(:,iw)+matrix_elements_resolvent(:,iw+1)))
781 :
782 264 : iw = iw+1
783 :
784 : end do !iw_prime
785 : end do !iw_ext
786 :
787 : end if
788 :
789 : end do !mb
790 : end do ! iblk
791 :
792 : ! sum on processors !
793 :
794 6 : call xmpi_sum(array_integrand, mpi_enreg%comm_bandfft, ierr) ! sum on all processors for LA configuration
795 :
796 : ! normalize !
797 78 : array_integrand(:,:) = array_integrand(:,:)/(2.0_dp*pi)
798 :
799 :
800 :
801 6 : call cleanup_LanczosResolvents
802 :
803 :
804 6 : ABI_FREE(psik_wrk)
805 6 : ABI_FREE(psikb_wrk)
806 6 : ABI_FREE(psikg_wrk)
807 :
808 6 : ABI_FREE(seed_vector)
809 6 : ABI_FREE(work_vec)
810 :
811 :
812 6 : ABI_FREE(right_vec_FFT)
813 6 : ABI_FREE(right_vec_LA)
814 :
815 6 : ABI_FREE(LR_M_matrix_LA)
816 :
817 6 : ABI_FREE(Hamiltonian_Qk_LA)
818 :
819 6 : ABI_FREE(real_wrk_vec)
820 6 : ABI_FREE(imag_wrk_vec)
821 6 : ABI_FREE(real_wrk_mat)
822 6 : ABI_FREE(imag_wrk_mat)
823 :
824 :
825 6 : ABI_FREE(shift_lanczos_matrix)
826 6 : ABI_FREE(left_vecs_LA)
827 :
828 :
829 6 : ABI_FREE(list_z)
830 6 : ABI_FREE(matrix_elements_resolvent)
831 :
832 6 : end subroutine compute_projected_BT_shift_Lanczos_DISTRIBUTED
833 : !!***
834 :
835 : end module m_gwls_Projected_BT
836 : !!***
|