LCOV - code coverage report
Current view: top level - src/70_gw - m_gwls_Projected_BT.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 99.1 % 223 221
Test Date: 2026-09-21 19:39:32 Functions: 100.0 % 2 2

            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              : !!***
        

Generated by: LCOV version 2.3-1