LCOV - code coverage report
Current view: top level - src/70_gw - m_gwls_Projected_AT.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 84.0 % 163 137
Test Date: 2026-09-21 13:49:52 Functions: 100.0 % 1 1

            Line data    Source code
       1              : !!****m* ABINIT/m_gwls_Projected_AT
       2              : !! NAME
       3              : !! m_gwls_Projected_AT
       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_AT
      24              : !----------------------------------------------------------------------------------------------------
      25              : ! This module contains routines to compute the matrix elements of the so-called A operator,
      26              : ! which accounts for the Static correlation energy term.
      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_LanczosResolvents
      37              : 
      38              : use m_gwls_GWanalyticPart, only : get_projection_band_indices
      39              : ! abinit modules
      40              : use defs_basis
      41              : use m_abicore
      42              : use m_xmpi
      43              : use m_io_tools,  only : get_unit
      44              : 
      45              : 
      46              : 
      47              : implicit none
      48              : save
      49              : private
      50              : !!***
      51              : 
      52              : !!***
      53              : 
      54              : ! Public methods
      55              : public :: compute_AT_shift_Lanczos
      56              : !!***
      57              : 
      58              : contains
      59              : 
      60              : !!****f* m_hamiltonian/compute_AT_shift_Lanczos
      61              : !! NAME
      62              : !!  compute_AT_shift_Lanczos
      63              : !!
      64              : !! FUNCTION
      65              : !!  .
      66              : !!
      67              : !! INPUTS
      68              : !!
      69              : !! OUTPUT
      70              : !!
      71              : !! SOURCE
      72              : 
      73           13 : subroutine compute_AT_shift_Lanczos(nfreq,list_external_omega,model_parameter,lmax, modified_Lbasis,kmax_analytic,list_AT_Lanczos)
      74              : !----------------------------------------------------------------------------------------------------
      75              : ! This function returns the diagonal matrix elements of the so-called A^T operator, which is pertinent to the
      76              : ! computation of the analytic energy term.
      77              : !
      78              : ! The operator is given by
      79              : !
      80              : !                 Am(W) = w0/2 Um^dagger  . [ PW/(H-W-w0)+QW/(H-W+w0)] . Um
      81              : !
      82              : !  where W is the external frequency of the self energy, and w0 is the lorentzian parameter.
      83              : !  The operator PW projects on states of energy lower than W, and QW on states or energy higher than W.
      84              : !
      85              : !
      86              : !  For every l, We seek to compute  AT_l = < l |  A^T | l > = < l^* | A | l^* >
      87              : !
      88              : !  It will be assumed that the array modified_Lbasis already contains the basis vectors U_m | l^* >.
      89              : !
      90              : !  This function does not use SQMR, but rather shift Lanczos to extract the values of the matrix elements for
      91              : !  all external frequencies.
      92              : !----------------------------------------------------------------------------------------------------
      93              : integer,      intent(in) :: nfreq
      94              : real(dp),     intent(in) :: list_external_omega(nfreq)
      95              : real(dp),     intent(in) :: model_parameter
      96              : integer,      intent(in) :: lmax
      97              : integer,      intent(in) :: kmax_analytic
      98              : complex(dp), intent(in) :: modified_Lbasis(npw_k,lmax)
      99              : complex(dp), intent(out):: list_AT_Lanczos(nfreq,lmax)
     100              : 
     101              : 
     102           13 : real(dp),     allocatable :: psik_wrk(:,:)
     103           13 : real(dp),     allocatable :: psikb_wrk(:,:)
     104           13 : real(dp),     allocatable :: psikg_wrk(:,:)
     105              : 
     106           13 : real(dp),     allocatable :: psikg(:,:)
     107              : 
     108           13 : complex(dp), allocatable :: seed_vector(:)
     109           13 : complex(dp), allocatable :: list_left_vectors(:,:)
     110           13 : complex(dp), allocatable :: matrix_elements_resolvent(:,:)
     111           13 : complex(dp), allocatable :: list_z_P(:), list_z_Q(:)
     112           13 : integer,      allocatable :: frequency_indices_array(:,:)
     113              : 
     114              : 
     115              : real(dp):: external_omega
     116              : logical :: prec
     117              : integer :: nvec
     118              : integer :: band_index_below, band_index_above, bib0, bia0, bib, bia
     119              : 
     120              : integer :: l, lloc, iw_ext, iw_ext_min, iw_ext_max
     121              : integer :: ierr
     122              : 
     123              : integer :: number_of_frequency_blocks, ifreq_block
     124              : 
     125              : integer :: iblk, nbdblock_lanczos
     126              : integer :: mb
     127              : 
     128              : integer :: nz
     129              : 
     130              : integer :: io_unit
     131              : integer :: mpi_band_rank
     132              : 
     133              : ! *************************************************************************
     134              : 
     135           13 : mpi_band_rank    = mpi_enreg%me_band
     136              : 
     137              : !=================================================
     138              : !
     139              : ! Find the number of frequency blocks, where
     140              : ! the projection operators are constant within a
     141              : ! block.
     142              : !=================================================
     143              : 
     144           13 : if (mpi_enreg%me == 0 ) then
     145            7 :   io_unit  = get_unit()
     146            7 :   open(io_unit,file='Frequency_blocks_AT.log',position='append')
     147              : 
     148            7 :   write(io_unit,10) "#================================================================================"
     149            7 :   write(io_unit,10) "#                                                                                "
     150            7 :   write(io_unit,10) "#  This log file documents how the algorithm in compute_AT_shift_Lanczos         "
     151            7 :   write(io_unit,10) "#  separates the external frequencies in blocks. It is quite easy to put         "
     152            7 :   write(io_unit,10) "#  bugs in this algorithm, so monitoring is critical.                            "
     153            7 :   write(io_unit,10) "#                                                                                "
     154            7 :   write(io_unit,10) "#================================================================================"
     155              : 
     156              : 
     157            7 :   write(io_unit,10) "                                                                                 "
     158            7 :   write(io_unit,10) "#================================================================================"
     159            7 :   write(io_unit,10) "#                                                                                "
     160            7 :   write(io_unit,10) "#  input parameters:                                                             "
     161            7 :   write(io_unit,10) "#                                                                                "
     162            7 :   write(io_unit,15) "#                      nfreq    : ",nfreq
     163            7 :   write(io_unit,17) "#          list_external_omega  : ",list_external_omega
     164            7 :   write(io_unit,17) "#              model_parameter  : ",model_parameter
     165            7 :   write(io_unit,15) "#                       lmax    : ",lmax
     166            7 :   write(io_unit,15) "#                kmax_analytic  : ",kmax_analytic
     167            7 :   write(io_unit,10) "#                                                                                "
     168            7 :   write(io_unit,10) "#================================================================================"
     169            7 :   write(io_unit,10) "#                                                                                "
     170            7 :   write(io_unit,10) "#  Building the blocks                                                           "
     171            7 :   write(io_unit,10) "#                                                                                "
     172            7 :   write(io_unit,10) "#         bib : band index below                                                 "
     173            7 :   write(io_unit,10) "#         bia : band index above                                                 "
     174            7 :   write(io_unit,10) "#         nfb : number_of_frequency_blocks                                       "
     175            7 :   write(io_unit,10) "#                                                                                "
     176            7 :   write(io_unit,10) "#                                                                                "
     177            7 :   write(io_unit,10) "#  iw_ext      external_omega (Ha)     bib  bia  nfb                             "
     178            7 :   write(io_unit,10) "#================================================================================"
     179              : end if
     180           13 : external_omega = list_external_omega(1)
     181              : 
     182              : 
     183              : ! bib == band_index_below
     184              : ! bia == band_index_above
     185           13 : call get_projection_band_indices(external_omega,bib0, bia0)
     186              : 
     187           13 : number_of_frequency_blocks = 1
     188              : 
     189              : ! loop on all external frequencies
     190           26 : do iw_ext = 1 , nfreq
     191              : 
     192           13 : external_omega = list_external_omega(iw_ext)
     193              : ! Define the energy of the state to be corrected
     194              : 
     195              : ! Find the indices for the projections PW and QW
     196           13 : call get_projection_band_indices(external_omega,bib, bia)
     197              : 
     198              : 
     199           13 : if (mpi_enreg%me == 0 ) write(io_unit,20) iw_ext, external_omega, bib, bia, number_of_frequency_blocks
     200              : 
     201           39 : if (bib /= bib0 .or. bia /= bia0) then
     202              : 
     203            0 :   if (mpi_enreg%me == 0 )   write(io_unit,10) "*************    new block!    **********************"
     204            0 :   bib0 = bib
     205            0 :   bia0 = bia
     206              : 
     207            0 :   number_of_frequency_blocks = number_of_frequency_blocks + 1
     208              : 
     209              : end if
     210              : end do
     211              : 
     212              : !=================================================
     213              : !
     214              : ! fill the frequency indices array
     215              : !
     216              : !=================================================
     217              : 
     218           13 : if (mpi_enreg%me == 0 ) then
     219            7 :   write(io_unit,10) "                                                                                 "
     220            7 :   write(io_unit,10) "#================================================================================"
     221            7 :   write(io_unit,10) "#                                                                                "
     222            7 :   write(io_unit,10) "#  Filling the frequency indices array                                           "
     223            7 :   write(io_unit,10) "#                                                                                "
     224            7 :   write(io_unit,10) "#  iw_ext      iw_ext_min     iw_ext_max  ifreq_block                            "
     225            7 :   write(io_unit,10) "#================================================================================"
     226              : end if
     227              : 
     228              : 
     229           39 : ABI_MALLOC(frequency_indices_array, (2,number_of_frequency_blocks))
     230           52 : frequency_indices_array = 0
     231              : 
     232           13 : iw_ext_min = 1
     233           13 : iw_ext_max = 1
     234              : 
     235              : ! loop on all external frequencies
     236           13 : external_omega = list_external_omega(1)
     237           13 : call get_projection_band_indices(external_omega,bib0, bia0)
     238           13 : ifreq_block = 1
     239              : 
     240           26 : do iw_ext = 1 , nfreq
     241              : 
     242           13 : if (mpi_enreg%me == 0 ) write(io_unit,30) iw_ext, iw_ext_min, iw_ext, ifreq_block
     243              : 
     244           13 : external_omega = list_external_omega(iw_ext)
     245              : ! Define the energy of the state to be corrected
     246              : 
     247              : ! Find the indices for the projections PW and QW
     248           13 : call get_projection_band_indices(external_omega,bib, bia)
     249              : 
     250           26 : if (bib /= bib0 .or. bia /= bia0) then
     251              : 
     252            0 :   if (mpi_enreg%me == 0 )   write(io_unit,10) "*************    new block!    **********************"
     253            0 :   bib0 = bib
     254            0 :   bia0 = bia
     255              : 
     256              :   ! write previous block
     257            0 :   frequency_indices_array(1,ifreq_block) = iw_ext_min
     258            0 :   frequency_indices_array(2,ifreq_block) = iw_ext-1 ! we went one too far
     259              : 
     260            0 :   ifreq_block  = ifreq_block  + 1
     261            0 :   iw_ext_min = iw_ext
     262              : end if
     263              : 
     264              : end do
     265              : 
     266              : ! write last block!
     267           13 : frequency_indices_array(1,ifreq_block) = iw_ext_min
     268           13 : frequency_indices_array(2,ifreq_block) = nfreq
     269              : 
     270           13 : if (mpi_enreg%me == 0 ) then
     271            7 :   write(io_unit,10) "                                                                                 "
     272            7 :   write(io_unit,10) "#================================================================================"
     273            7 :   write(io_unit,10) "#                                                                                "
     274            7 :   write(io_unit,10) "#                                                                                "
     275            7 :   write(io_unit,10) "#  Final frequency_indices_array :                                               "
     276            7 :   write(io_unit,10) "#                                                                                "
     277            7 :   write(io_unit,10) "#  ifreq_block iw_ext_min     iw_ext_max                                         "
     278            7 :   write(io_unit,10) "#================================================================================"
     279              : 
     280           14 :   do ifreq_block = 1 , number_of_frequency_blocks
     281              : 
     282           14 :   write(io_unit,40) ifreq_block, frequency_indices_array(1,ifreq_block), frequency_indices_array(2,ifreq_block)
     283              : 
     284              :   end do
     285              : end if
     286              : 
     287              : 
     288              : 
     289              : 
     290              : !=================================================
     291              : !
     292              : ! Set up the LanczosResolvents algorithm
     293              : !
     294              : !=================================================
     295              : 
     296           13 : prec = .false.  ! let's not precondition for now
     297           13 : call setup_LanczosResolvents(kmax_analytic, prec)
     298              : 
     299              : !=================================================
     300              : !
     301              : ! iterate on frequency blocks!
     302              : !
     303              : !=================================================
     304           13 : nvec = 1
     305              : 
     306           39 : ABI_MALLOC(list_left_vectors, (npw_g,nvec))
     307           39 : ABI_MALLOC(seed_vector, (npw_g))
     308              : 
     309           39 : ABI_MALLOC(psik_wrk,  (2,npw_k))
     310           39 : ABI_MALLOC(psikb_wrk, (2,npw_kb))
     311              : 
     312           39 : ABI_MALLOC(psikg_wrk, (2,npw_g))
     313           26 : ABI_MALLOC(psikg,     (2,npw_g))
     314              : 
     315          221 : list_AT_Lanczos(:,:) = cmplx_0
     316              : 
     317              : ! Number of blocks of lanczos vectors
     318           13 : nbdblock_lanczos = lmax/blocksize
     319           13 : if (modulo(lmax,blocksize) /= 0) nbdblock_lanczos = nbdblock_lanczos + 1
     320              : 
     321              : 
     322           26 : do ifreq_block = 1, number_of_frequency_blocks
     323              : 
     324              : !-------------------------------
     325              : ! Build the frequency arrays
     326              : !-------------------------------
     327           13 : iw_ext_min = frequency_indices_array(1,ifreq_block)
     328           13 : iw_ext_max = frequency_indices_array(2,ifreq_block)
     329              : 
     330              : 
     331           13 : nz = iw_ext_max -iw_ext_min + 1
     332              : 
     333           39 : ABI_MALLOC( list_z_P, (nz))
     334           26 : ABI_MALLOC( list_z_Q, (nz))
     335           26 : ABI_MALLOC(matrix_elements_resolvent, (nz,nvec))
     336              : 
     337              : 
     338           13 : external_omega = list_external_omega(iw_ext_min)
     339           13 : call get_projection_band_indices(external_omega,band_index_below, band_index_above)
     340              : 
     341              : 
     342           26 : do iw_ext = iw_ext_min, iw_ext_max
     343              : 
     344           13 : list_z_P(iw_ext-iw_ext_min+1) = list_external_omega(iw_ext)+ model_parameter
     345           26 : list_z_Q(iw_ext-iw_ext_min+1) = list_external_omega(iw_ext)- model_parameter
     346              : 
     347              : end do
     348              : 
     349              : !-----------------------------------------
     350              : ! Compute with shift Lanczos, using blocks
     351              : !-----------------------------------------
     352           85 : do iblk = 1, nbdblock_lanczos
     353              : ! which l is on this row of FFT processors?
     354           72 : l = (iblk-1)*blocksize + mpi_band_rank + 1
     355              : 
     356              : ! Change the configuration of the data
     357          176 : do mb =1, blocksize
     358          104 : lloc = (iblk-1)*blocksize+mb
     359          104 : if (lloc <= lmax) then
     360        14496 :   psik_wrk(1,:)  = dble ( modified_Lbasis(:,lloc) )
     361        14496 :   psik_wrk(2,:)  = dimag( modified_Lbasis(:,lloc) )
     362              : else
     363            0 :   psik_wrk(:,:)  = zero
     364              : end if
     365              : 
     366        43352 : psikb_wrk(:,(mb-1)*npw_k+1:mb*npw_k) = psik_wrk(:,:)
     367              : 
     368              : end do ! mb
     369              : 
     370              : ! change configuration of the data, from LA to FFT
     371           72 : call wf_block_distribute(psikb_wrk,  psikg_wrk, 1) ! LA -> FFT
     372              : 
     373              : 
     374           85 : if (band_index_below == 0 .and. l <= lmax) then
     375              :   ! There are no DFT states with energy below W!
     376              :   ! PW is thus zero, and QW = I.
     377              : 
     378        14464 :   seed_vector(:)         = cmplx_1*psikg_wrk(1,:) + cmplx_i*psikg_wrk(2,:)
     379        14464 :   list_left_vectors(:,1) = seed_vector(:)
     380              : 
     381              :   call compute_resolvent_column_shift_lanczos(nz, list_z_Q, nvec, list_left_vectors, seed_vector, &
     382           72 :   &                                                                   matrix_elements_resolvent)
     383              : 
     384          144 :   list_AT_Lanczos(iw_ext_min:iw_ext_max, l) = 0.5_dp*model_parameter*matrix_elements_resolvent(:,1)
     385              : 
     386              : 
     387            0 : else if ( l <= lmax ) then
     388              : 
     389              :   !----------------------------------------------------------------------------------
     390              :   !
     391              :   ! CAREFUL HERE! PW + QW != I. If the external frequency is exactly equal to a
     392              :   !               DFT eigenvalue, then the projections PW and QW both project OUT
     393              :   !               of the subspace corresponding to this energy!
     394              :   !
     395              :   !----------------------------------------------------------------------------------
     396              : 
     397              :   !-------------------
     398              :   ! Treat first PW
     399              :   !-------------------
     400            0 :   psikg(:,:) = psikg_wrk(:,:)
     401            0 :   call pc_k_valence_kernel(psikg,band_index_below)
     402              : 
     403            0 :   seed_vector = cmplx_1*psikg(1,:)+cmplx_i*psikg(2,:)
     404              : 
     405            0 :   list_left_vectors(:,1) = seed_vector(:)
     406              : 
     407              :   call compute_resolvent_column_shift_lanczos(nz, list_z_P, nvec, list_left_vectors, seed_vector, &
     408            0 :   &                                                                   matrix_elements_resolvent)
     409              : 
     410            0 :   list_AT_Lanczos(iw_ext_min:iw_ext_max, l) = 0.5_dp*model_parameter*matrix_elements_resolvent(:,1)
     411              : 
     412              : 
     413              :   !-------------------
     414              :   ! Treat second QW
     415              :   !-------------------
     416              : 
     417            0 :   psikg(:,:) = psikg_wrk(:,:)
     418              : 
     419            0 :   call pc_k_valence_kernel(psikg,band_index_above)
     420              : 
     421            0 :   psikg(:,:) = psikg_wrk(:,:)-psikg(:,:)
     422              : 
     423            0 :   seed_vector = cmplx_1*psikg(1,:)+cmplx_i*psikg(2,:)
     424              : 
     425            0 :   list_left_vectors(:,1) = seed_vector(:)
     426              : 
     427              :   call compute_resolvent_column_shift_lanczos(nz, list_z_Q, nvec, list_left_vectors, seed_vector, &
     428            0 :   &                                                                   matrix_elements_resolvent)
     429              : 
     430              :   list_AT_Lanczos(iw_ext_min:iw_ext_max, l) = list_AT_Lanczos(iw_ext_min:iw_ext_max, l) +   &
     431            0 :   0.5_dp*model_parameter*matrix_elements_resolvent(:,1)
     432              : 
     433              : end if
     434              : 
     435              : end do
     436              : 
     437           13 : ABI_FREE( list_z_P)
     438           13 : ABI_FREE( list_z_Q)
     439           39 : ABI_FREE(matrix_elements_resolvent)
     440              : 
     441              : end do
     442              : 
     443              : 
     444              : ! sum all results
     445           13 : call xmpi_sum(list_AT_Lanczos, mpi_enreg%comm_band,ierr) ! sum on all processors working on bands
     446              : 
     447              : 
     448           13 : if (mpi_enreg%me == 0 ) then
     449            7 :   close(io_unit)
     450              : end if
     451              : 
     452           13 : ABI_FREE(list_left_vectors)
     453           13 : ABI_FREE(seed_vector)
     454           13 : ABI_FREE(frequency_indices_array)
     455              : 
     456              : 
     457           13 : ABI_FREE(psik_wrk)
     458           13 : ABI_FREE(psikb_wrk)
     459              : 
     460           13 : ABI_FREE(psikg_wrk)
     461           13 : ABI_FREE(psikg)
     462              : 
     463              : 
     464              : 
     465              : 
     466           13 : call cleanup_LanczosResolvents
     467              : 
     468              : 10 format(A)
     469              : 15 format(A,I5)
     470              : 17 format(A,1000F8.4)
     471              : 20 format(I5,7X,ES24.16,3I5)
     472              : 30 format(4(I5,10X))
     473              : 40 format(3(I5,10x))
     474              : 
     475           26 : end subroutine compute_AT_shift_Lanczos
     476              : !!***
     477              : 
     478              : 
     479              : end module m_gwls_Projected_AT
     480              : !!***
        

Generated by: LCOV version 2.3-1